From 8a46931399fe1cdec4f1dcbf0388446020dd6e5c Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 27 Jun 2021 10:55:18 -0700 Subject: [PATCH 001/114] !!!!WIP!!!! adding InfluxDB - influxdb added to dockerfile - influxdb s6 service - influxdb config - adding defaults to config - creating a DeviceRepo interface (multiple db backends) - implemented DeviceRepo interface as ScruitnyRepository --- CONTRIBUTING.md | 27 + docker/Dockerfile | 5 + docker/entrypoint-collector.sh | 2 +- docs/dbdiagram.io.txt | 62 + example.scrutiny.yaml | 7 +- go.mod | 2 + go.sum | 40 + rootfs/etc/services.d/influxdb/run | 4 + rootfs/scrutiny/influxdb/config.yaml | 4 + webapp/backend/pkg/config/config.go | 7 + webapp/backend/pkg/constants.go | 28 + webapp/backend/pkg/database/interface.go | 27 + .../pkg/database/scrutiny_repository.go | 436 ++ .../pkg/metadata/ata_attribute_metadata.go | 10 +- .../pkg/metadata/nvme_attribute_metadata.go | 6 +- .../pkg/metadata/scsi_attribute_metadata.go | 54 +- webapp/backend/pkg/models/collector/smart.go | 80 +- webapp/backend/pkg/models/db/device.go | 160 - webapp/backend/pkg/models/db/selftest.go | 15 - webapp/backend/pkg/models/db/smart.go | 127 - .../pkg/models/db/smart_ata_attribute.go | 111 - .../pkg/models/db/smart_nvme_attribute.go | 46 - .../pkg/models/db/smart_scsci_attribute.go | 45 - webapp/backend/pkg/models/db/smart_test.go | 155 - webapp/backend/pkg/models/device.go | 169 + webapp/backend/pkg/models/device_summary.go | 19 + .../backend/pkg/models/measurements/smart.go | 198 + .../measurements/smart_ata_attribute.go | 151 + .../models/measurements/smart_attribute.go | 6 + .../measurements/smart_nvme_attribute.go | 68 + .../measurements/smart_scsci_attribute.go | 67 + .../models/measurements/smart_temperature.go | 29 + .../pkg/models/measurements/smart_test.go | 141 + webapp/backend/pkg/models/setting.go | 5 + .../pkg/models/testdata/smart-ata-date.json | 846 +++ .../pkg/web/handler/get_device_details.go | 31 +- .../pkg/web/handler/get_devices_summary.go | 21 +- .../pkg/web/handler/register_devices.go | 20 +- .../pkg/web/handler/send_test_notification.go | 7 +- .../pkg/web/handler/upload_device_metrics.go | 36 +- .../backend/pkg/web/middleware/repository.go | 22 + webapp/backend/pkg/web/middleware/sqlite3.go | 59 - webapp/backend/pkg/web/server.go | 2 +- webapp/backend/pkg/web/server_test.go | 4 +- .../src/app/data/mock/device/details/sda.ts | 1550 +----- .../src/app/data/mock/device/details/sdb.ts | 4664 ++--------------- .../src/app/data/mock/device/details/sdc.ts | 2306 +------- .../src/app/data/mock/device/details/sdd.ts | 1316 +---- .../src/app/data/mock/summary/data.ts | 1403 +++-- .../dashboard/dashboard.component.html | 42 +- .../modules/dashboard/dashboard.component.ts | 25 +- .../app/modules/detail/detail.component.html | 42 +- .../app/modules/detail/detail.component.ts | 69 +- 53 files changed, 4181 insertions(+), 10597 deletions(-) create mode 100644 docs/dbdiagram.io.txt create mode 100644 rootfs/etc/services.d/influxdb/run create mode 100644 rootfs/scrutiny/influxdb/config.yaml create mode 100644 webapp/backend/pkg/constants.go create mode 100644 webapp/backend/pkg/database/interface.go create mode 100644 webapp/backend/pkg/database/scrutiny_repository.go delete mode 100644 webapp/backend/pkg/models/db/device.go delete mode 100644 webapp/backend/pkg/models/db/selftest.go delete mode 100644 webapp/backend/pkg/models/db/smart.go delete mode 100644 webapp/backend/pkg/models/db/smart_ata_attribute.go delete mode 100644 webapp/backend/pkg/models/db/smart_nvme_attribute.go delete mode 100644 webapp/backend/pkg/models/db/smart_scsci_attribute.go delete mode 100644 webapp/backend/pkg/models/db/smart_test.go create mode 100644 webapp/backend/pkg/models/device.go create mode 100644 webapp/backend/pkg/models/device_summary.go create mode 100644 webapp/backend/pkg/models/measurements/smart.go create mode 100644 webapp/backend/pkg/models/measurements/smart_ata_attribute.go create mode 100644 webapp/backend/pkg/models/measurements/smart_attribute.go create mode 100644 webapp/backend/pkg/models/measurements/smart_nvme_attribute.go create mode 100644 webapp/backend/pkg/models/measurements/smart_scsci_attribute.go create mode 100644 webapp/backend/pkg/models/measurements/smart_temperature.go create mode 100644 webapp/backend/pkg/models/measurements/smart_test.go create mode 100644 webapp/backend/pkg/models/setting.go create mode 100644 webapp/backend/pkg/models/testdata/smart-ata-date.json create mode 100644 webapp/backend/pkg/web/middleware/repository.go delete mode 100644 webapp/backend/pkg/web/middleware/sqlite3.go diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 294bc04..034d407 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -71,6 +71,33 @@ go run webapp/backend/cmd/scrutiny/scrutiny.go start --config ./scrutiny.yaml Now visit http://localhost:8080 +If you'd like to populate the database with some test data, you can run the following commands: + +``` +docker run -p 8086:8086 --rm influxdb:2.0 + + +docker run -p 8086:8086 \ + -e DOCKER_INFLUXDB_INIT_USERNAME=admin \ + -e DOCKER_INFLUXDB_INIT_PASSWORD=12345678 \ + -e DOCKER_INFLUXDB_INIT_ORG=my-org \ + -e DOCKER_INFLUXDB_INIT_BUCKET=bucket \ + influxdb:2.0 + + +curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/web/testdata/register-devices-req.json localhost:8080/api/devices/register + +curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-ata.json localhost:8080/api/device/0x5000cca264eb01d7/smart +curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-ata-date.json localhost:8080/api/device/0x5000cca264eb01d7/smart +curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-fail2.json localhost:8080/api/device/0x5000cca264ec3183/smart +curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-nvme.json localhost:8080/api/device/0x5002538e40a22954/smart +curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-scsi.json localhost:8080/api/device/0x5000cca252c859cc/smart +curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-scsi2.json localhost:8080/api/device/0x5000cca264ebc248/smart + +curl localhost:8080/api/summary + +``` + ### Collector ``` brew install smartmontools diff --git a/docker/Dockerfile b/docker/Dockerfile index 5409a22..235ff60 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -30,11 +30,16 @@ FROM ubuntu:bionic as runtime EXPOSE 8080 WORKDIR /scrutiny ENV PATH="/scrutiny/bin:${PATH}" +ENV INFLUXD_CONFIG_PATH=/scrutiny/influxdb RUN apt-get update && apt-get install -y cron smartmontools=7.0-0ubuntu1~ubuntu18.04.1 ca-certificates curl && update-ca-certificates ADD https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s6-overlay-amd64.tar.gz /tmp/ RUN tar xzf /tmp/s6-overlay-amd64.tar.gz -C / + +ADD https://dl.influxdata.com/influxdb/releases/influxdb2-2.0.4-amd64.deb /tmp/ +RUN dpkg -i /tmp/influxdb2-2.0.4-amd64.deb && rm -rf /tmp/influxdb2-2.0.4-amd64.deb + COPY /rootfs / COPY /rootfs/etc/cron.d/scrutiny /etc/cron.d/scrutiny diff --git a/docker/entrypoint-collector.sh b/docker/entrypoint-collector.sh index c838c19..501c8d5 100755 --- a/docker/entrypoint-collector.sh +++ b/docker/entrypoint-collector.sh @@ -7,4 +7,4 @@ printenv | sed 's/^\(.*\)$/export \1/g' > /env.sh # now that we have the env start cron in the foreground echo "starting cron" -cron -f +su -c "cron -l 8 -f" root diff --git a/docs/dbdiagram.io.txt b/docs/dbdiagram.io.txt new file mode 100644 index 0000000..7d23af7 --- /dev/null +++ b/docs/dbdiagram.io.txt @@ -0,0 +1,62 @@ + +// SQLite Table(s) +Table device { + created_at timestamp + + wwn varchar [pk] + + //user provided + label varchar + host_id varchar + + // smartctl provided + device_name varchar + manufacturer varchar + model_name varchar + interface_type varchar + interface_speed varchar + serial_number varchar + firmware varchar + rotational_speed varchar + capacity varchar + form_factor varchar + smart_support varchar + device_protocol varchar + device_type varchar + +} + + +// InfluxDB Tables +Table device_temperature { + //timestamp + created_at timestamp + + //tags (indexed & queryable) + device_wwn varchar [pk] + + //fields + temp bigint + } + + +Table smart_ata_results { + //timestamp + created_at timestamp + + //tags (indexed & queryable) + device_wwn varchar [pk] + smart_status varchar + scrutiny_status varchar + + + + //fields + temp bigint + power_on_hours bigint + power_cycle_count bigint + + + } + +Ref: device.wwn < smart_ata_results.device_wwn diff --git a/example.scrutiny.yaml b/example.scrutiny.yaml index 9744f19..f7460ed 100644 --- a/example.scrutiny.yaml +++ b/example.scrutiny.yaml @@ -26,7 +26,12 @@ web: src: frontend: path: /scrutiny/web - + influxdb: + host: 0.0.0.0 + port: 8086 +# token: 'my-token' +# org: 'my-org' +# bucket: 'bucket' log: file: '' #absolute or relative paths allowed, eg. web.log diff --git a/go.mod b/go.mod index 013e908..d8d1baf 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,8 @@ require ( github.com/gin-gonic/gin v1.6.3 github.com/golang/mock v1.4.3 github.com/google/uuid v1.2.0 // indirect + github.com/hashicorp/serf v0.8.2 + github.com/influxdata/influxdb-client-go/v2 v2.2.3 github.com/jaypipes/ghw v0.6.1 github.com/klauspost/compress v1.12.1 // indirect github.com/kvz/logstreamer v0.0.0-20150507115422-a635b98146f0 // indirect diff --git a/go.sum b/go.sum index fbdbed6..8ea4b43 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,7 @@ github.com/analogj/go-util v0.0.0-20190301173314-5295e364eb14 h1:wsrSjiqQtseStRI github.com/analogj/go-util v0.0.0-20190301173314-5295e364eb14/go.mod h1:lJQVqFKMV5/oDGYR2bra2OljcF3CvolAoyDRyOA4k4E= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -53,9 +54,12 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSY github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deepmap/oapi-codegen v1.3.13 h1:9HKGCsdJqE4dnrQ8VerFS0/1ZOJPmAhN+g8xgp8y3K4= +github.com/deepmap/oapi-codegen v1.3.13/go.mod h1:WAmG5dWY8/PYHt4vKxlt90NsbHMAOCiteYKZMiIRfOo= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= @@ -69,12 +73,14 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-interpreter/wagon v0.5.1-0.20190713202023-55a163980b6c/go.mod h1:5+b/MBYkclRZngKF5s6qrgWxSLgE9F5dFdO1hAueZLc= github.com/go-interpreter/wagon v0.6.0/go.mod h1:5+b/MBYkclRZngKF5s6qrgWxSLgE9F5dFdO1hAueZLc= @@ -119,7 +125,9 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= @@ -149,28 +157,42 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb-client-go v1.4.0 h1:+KavOkwhLClHFfYcJMHHnTL5CZQhXJzOm5IKHI9BqJk= +github.com/influxdata/influxdb-client-go/v2 v2.2.3 h1:082jdJ5t1CFeo0rpGQvKAK1mONVSbFhL4finWA5bRM8= +github.com/influxdata/influxdb-client-go/v2 v2.2.3/go.mod h1:fa/d1lAdUHxuc1jedx30ZfNG573oQTQmUni3N6pcW+0= +github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= +github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/jarcoal/httpmock v1.0.4 h1:jp+dy/+nonJE4g4xbVtl9QdrUNbn6/3hDT5R4nDIZnA= github.com/jarcoal/httpmock v1.0.4/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jaypipes/ghw v0.6.1 h1:Ewt3mdpiyhWotGyzg1ursV/6SnToGcG4215X6rR2af8= @@ -210,6 +232,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kvz/logstreamer v0.0.0-20150507115422-a635b98146f0 h1:3tLzEnUizyN9YLWFTT9loC30lSBvh2y70LTDcZOTs1s= github.com/kvz/logstreamer v0.0.0-20150507115422-a635b98146f0/go.mod h1:8/LTPeDLaklcUjgSQBHbhBF1ibKAFxzS5o+H7USfMSA= +github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -220,6 +244,7 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= @@ -229,6 +254,7 @@ github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -237,6 +263,7 @@ github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGw github.com/mattn/go-sqlite3 v1.14.4 h1:4rQjbDxdu9fSgI/r3KN72G3c2goxknAqHHgPWWs8UlI= github.com/mattn/go-sqlite3 v1.14.4/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -284,6 +311,8 @@ github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAv github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= @@ -301,6 +330,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -357,6 +387,9 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -373,7 +406,9 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= @@ -414,9 +449,11 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -454,7 +491,9 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190927073244-c990c680b611/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -498,6 +537,7 @@ golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/rootfs/etc/services.d/influxdb/run b/rootfs/etc/services.d/influxdb/run new file mode 100644 index 0000000..e862aaa --- /dev/null +++ b/rootfs/etc/services.d/influxdb/run @@ -0,0 +1,4 @@ +#!/usr/bin/with-contenv bash + +echo "starting influxdb" +influxd run diff --git a/rootfs/scrutiny/influxdb/config.yaml b/rootfs/scrutiny/influxdb/config.yaml new file mode 100644 index 0000000..245d541 --- /dev/null +++ b/rootfs/scrutiny/influxdb/config.yaml @@ -0,0 +1,4 @@ +bolt-path: /scrutiny/influxdb/influxd.bolt +engine-path: /scrutiny/influxdb/engine +http-bind-address: ":8086" +reporting-disabled: true diff --git a/webapp/backend/pkg/config/config.go b/webapp/backend/pkg/config/config.go index 6349b55..beccb90 100644 --- a/webapp/backend/pkg/config/config.go +++ b/webapp/backend/pkg/config/config.go @@ -37,6 +37,13 @@ func (c *configuration) Init() error { c.SetDefault("notify.urls", []string{}) + c.SetDefault("web.influxdb.host", "0.0.0.0") + c.SetDefault("web.influxdb.port", "8086") + c.SetDefault("web.influxdb.org", "scrutiny") + c.SetDefault("web.influxdb.bucket", "metrics") + c.SetDefault("web.influxdb.init_username", "admin") + c.SetDefault("web.influxdb.init_password", "password12345") + //c.SetDefault("disks.include", []string{}) //c.SetDefault("disks.exclude", []string{}) diff --git a/webapp/backend/pkg/constants.go b/webapp/backend/pkg/constants.go new file mode 100644 index 0000000..83ab99b --- /dev/null +++ b/webapp/backend/pkg/constants.go @@ -0,0 +1,28 @@ +package pkg + +const DeviceProtocolAta = "ATA" +const DeviceProtocolScsi = "SCSI" +const DeviceProtocolNvme = "NVMe" + +const SmartAttributeStatusPassed = "passed" +const SmartAttributeStatusFailed = "failed" +const SmartAttributeStatusWarning = "warn" + +const SmartWhenFailedFailingNow = "FAILING_NOW" +const SmartWhenFailedInThePast = "IN_THE_PAST" + +//const SmartStatusPassed = "passed" +//const SmartStatusFailed = "failed" + +type DeviceStatus int + +const ( + DeviceStatusPassed DeviceStatus = 0 + DeviceStatusFailedSmart DeviceStatus = iota + DeviceStatusFailedScrutiny DeviceStatus = iota +) + +func Set(b, flag DeviceStatus) DeviceStatus { return b | flag } +func Clear(b, flag DeviceStatus) DeviceStatus { return b &^ flag } +func Toggle(b, flag DeviceStatus) DeviceStatus { return b ^ flag } +func Has(b, flag DeviceStatus) bool { return b&flag != 0 } diff --git a/webapp/backend/pkg/database/interface.go b/webapp/backend/pkg/database/interface.go new file mode 100644 index 0000000..5bca804 --- /dev/null +++ b/webapp/backend/pkg/database/interface.go @@ -0,0 +1,27 @@ +package database + +import ( + "context" + "github.com/analogj/scrutiny/webapp/backend/pkg/models" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" +) + +type DeviceRepo interface { + Close() error + + //GetSettings() + //SaveSetting() + + RegisterDevice(ctx context.Context, dev models.Device) error + GetDevices(ctx context.Context) ([]models.Device, error) + UpdateDevice(ctx context.Context, wwn string, collectorSmartData collector.SmartInfo) (models.Device, error) + GetDeviceDetails(ctx context.Context, wwn string) (models.Device, error) + + SaveSmartAttributes(ctx context.Context, wwn string, collectorSmartData collector.SmartInfo) (measurements.Smart, error) + GetSmartAttributeHistory(ctx context.Context, wwn string, startAt string, attributes []string) ([]measurements.Smart, error) + + SaveSmartTemperature(ctx context.Context, wwn string, deviceProtocol string, collectorSmartData collector.SmartInfo) error + + GetSummary(ctx context.Context) (map[string]*models.DeviceSummary, error) +} diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go new file mode 100644 index 0000000..a7711c1 --- /dev/null +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -0,0 +1,436 @@ +package database + +import ( + "context" + "fmt" + "github.com/analogj/scrutiny/webapp/backend/pkg/config" + "github.com/analogj/scrutiny/webapp/backend/pkg/models" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" + influxdb2 "github.com/influxdata/influxdb-client-go/v2" + "github.com/influxdata/influxdb-client-go/v2/api" + "github.com/sirupsen/logrus" + "gorm.io/driver/sqlite" + "gorm.io/gorm" + "gorm.io/gorm/clause" + "time" +) + +//// GormLogger is a custom logger for Gorm, making it use logrus. +//type GormLogger struct{ Logger logrus.FieldLogger } +// +//// Print handles log events from Gorm for the custom logger. +//func (gl *GormLogger) Print(v ...interface{}) { +// switch v[0] { +// case "sql": +// gl.Logger.WithFields( +// logrus.Fields{ +// "module": "gorm", +// "type": "sql", +// "rows": v[5], +// "src_ref": v[1], +// "values": v[4], +// }, +// ).Debug(v[3]) +// case "log": +// gl.Logger.WithFields(logrus.Fields{"module": "gorm", "type": "log"}).Print(v[2]) +// } +//} + +func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.FieldLogger) (DeviceRepo, error) { + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Gorm/SQLite setup + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + fmt.Printf("Trying to connect to database stored: %s\n", appConfig.GetString("web.database.location")) + database, err := gorm.Open(sqlite.Open(appConfig.GetString("web.database.location")), &gorm.Config{ + //TODO: figure out how to log database queries again. + //Logger: logger + }) + if err != nil { + return nil, fmt.Errorf("Failed to connect to database!") + } + + //database.SetLogger() + database.AutoMigrate(&models.Device{}) + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // InfluxDB setup + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // Create a new client using an InfluxDB server base URL and an authentication token + influxdbUrl := fmt.Sprintf("http://%s:%s", appConfig.GetString("web.influxdb.host"), appConfig.GetString("web.influxdb.port")) + globalLogger.Debugf("InfluxDB url: %s", influxdbUrl) + + client := influxdb2.NewClient(influxdbUrl, appConfig.GetString("web.influxdb.token")) + + if !appConfig.IsSet("web.influxdb.token") { + globalLogger.Debugf("No influxdb token found, running first-time setup...") + + // if no token is provided, but we have a valid server, we're going to assume this is the first setup of our server. + // we will initialize with a predetermined username & password, that you should change. + onboardingResponse, err := client.Setup( + context.Background(), + appConfig.GetString("web.influxdb.init_username"), + appConfig.GetString("web.influxdb.init_password"), + appConfig.GetString("web.influxdb.org"), + appConfig.GetString("web.influxdb.bucket"), + 0) + if err != nil { + return nil, err + } + + appConfig.Set("web.influxdb.token", *onboardingResponse.Auth.Token) + //todo: determine if we should write the config file out here. + } + + // Use blocking write client for writes to desired bucket + writeAPI := client.WriteAPIBlocking(appConfig.GetString("web.influxdb.org"), appConfig.GetString("web.influxdb.bucket")) + + // Get query client + queryAPI := client.QueryAPI(appConfig.GetString("web.influxdb.org")) + + if writeAPI == nil || queryAPI == nil { + return nil, fmt.Errorf("Failed to connect to influxdb!") + } + + deviceRepo := scrutinyRepository{ + appConfig: appConfig, + logger: globalLogger, + influxClient: client, + influxWriteApi: writeAPI, + influxQueryApi: queryAPI, + gormClient: database, + } + + return &deviceRepo, nil +} + +type scrutinyRepository struct { + appConfig config.Interface + logger logrus.FieldLogger + + influxWriteApi api.WriteAPIBlocking + influxQueryApi api.QueryAPI + influxClient influxdb2.Client + + gormClient *gorm.DB +} + +func (sr *scrutinyRepository) Close() error { + sr.influxClient.Close() + return nil +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Device +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//insert device into DB (and update specified columns if device is already registered) +// update device fields that may change: (DeviceType, HostID) +func (sr *scrutinyRepository) RegisterDevice(ctx context.Context, dev models.Device) error { + if err := sr.gormClient.WithContext(ctx).Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "wwn"}}, + DoUpdates: clause.AssignmentColumns([]string{"host_id", "device_name", "device_type"}), + }).Create(&dev).Error; err != nil { + return err + } + return nil +} + +// get a list of all devices (only device metadata, no SMART data) +func (sr *scrutinyRepository) GetDevices(ctx context.Context) ([]models.Device, error) { + //Get a list of all the active devices. + devices := []models.Device{} + if err := sr.gormClient.WithContext(ctx).Find(&devices).Error; err != nil { + return nil, fmt.Errorf("Could not get device summary from DB", err) + } + return devices, nil +} + +// update device (only metadata) from collector +func (sr *scrutinyRepository) UpdateDevice(ctx context.Context, wwn string, collectorSmartData collector.SmartInfo) (models.Device, error) { + var device models.Device + if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil { + return device, fmt.Errorf("Could not get device from DB", err) + } + + //TODO catch GormClient err + err := device.UpdateFromCollectorSmartInfo(collectorSmartData) + if err != nil { + return device, err + } + return device, sr.gormClient.Model(&device).Updates(device).Error +} + +func (sr *scrutinyRepository) GetDeviceDetails(ctx context.Context, wwn string) (models.Device, error) { + var device models.Device + + fmt.Println("GetDeviceDetails from GORM") + + if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil { + return models.Device{}, err + } + + return device, nil +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SMART +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +func (sr *scrutinyRepository) SaveSmartAttributes(ctx context.Context, wwn string, collectorSmartData collector.SmartInfo) (measurements.Smart, error) { + deviceSmartData := measurements.Smart{} + err := deviceSmartData.FromCollectorSmartInfo(wwn, collectorSmartData) + if err != nil { + sr.logger.Errorln("Could not process SMART metrics", err) + return measurements.Smart{}, err + } + + tags, fields := deviceSmartData.Flatten() + p := influxdb2.NewPoint("smart", + tags, + fields, + deviceSmartData.Date) + + // write point immediately + return deviceSmartData, sr.influxWriteApi.WritePoint(ctx, p) +} + +func (sr *scrutinyRepository) GetSmartAttributeHistory(ctx context.Context, wwn string, startAt string, attributes []string) ([]measurements.Smart, error) { + // Get SMartResults from InfluxDB + + fmt.Println("GetDeviceDetails from INFLUXDB") + + //TODO: change the filter startrange to a real number. + + // Get parser flux query result + //appConfig.GetString("web.influxdb.bucket") + queryStr := fmt.Sprintf(` + import "influxdata/influxdb/schema" + from(bucket: "%s") + |> range(start: -2y, stop: now()) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> filter(fn: (r) => r["device_wwn"] == "%s" ) + |> schema.fieldsAsCols() + |> group(columns: ["device_wwn"]) + |> yield(name: "last") + `, + sr.appConfig.GetString("web.influxdb.bucket"), + wwn, + ) + + smartResults := []measurements.Smart{} + + result, err := sr.influxQueryApi.Query(ctx, queryStr) + if err == nil { + fmt.Println("GetDeviceDetails NO EROR") + + // Use Next() to iterate over query result lines + for result.Next() { + fmt.Println("GetDeviceDetails NEXT") + + // Observe when there is new grouping key producing new table + if result.TableChanged() { + //fmt.Printf("table: %s\n", result.TableMetadata().String()) + } + + fmt.Printf("DECODINIG TABLE VALUES: %v", result.Record().Values()) + smartData, err := measurements.NewSmartFromInfluxDB(result.Record().Values()) + if err != nil { + return nil, err + } + smartResults = append(smartResults, *smartData) + + } + if result.Err() != nil { + fmt.Printf("Query error: %s\n", result.Err().Error()) + } + } else { + return nil, err + } + + return smartResults, nil + + //if err := device.SquashHistory(); err != nil { + // logger.Errorln("An error occurred while squashing device history", err) + // c.JSON(http.StatusInternalServerError, gin.H{"success": false}) + // return + //} + // + //if err := device.ApplyMetadataRules(); err != nil { + // logger.Errorln("An error occurred while applying scrutiny thresholds & rules", err) + // c.JSON(http.StatusInternalServerError, gin.H{"success": false}) + // return + //} + +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Temperature Data +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +func (sr *scrutinyRepository) SaveSmartTemperature(ctx context.Context, wwn string, deviceProtocol string, collectorSmartData collector.SmartInfo) error { + if len(collectorSmartData.AtaSctTemperatureHistory.Table) > 0 { + + for ndx, temp := range collectorSmartData.AtaSctTemperatureHistory.Table { + + minutesOffset := collectorSmartData.AtaSctTemperatureHistory.LoggingIntervalMinutes * int64(ndx) * 60 + smartTemp := measurements.SmartTemperature{ + Date: time.Unix(collectorSmartData.LocalTime.TimeT-minutesOffset, 0), + Temp: temp, + } + + tags, fields := smartTemp.Flatten() + tags["device_wwn"] = wwn + p := influxdb2.NewPoint("temp", + tags, + fields, + smartTemp.Date) + err := sr.influxWriteApi.WritePoint(ctx, p) + if err != nil { + return err + } + } + // also add the current temperature. + } else { + + smartTemp := measurements.SmartTemperature{ + Date: time.Unix(collectorSmartData.LocalTime.TimeT, 0), + Temp: collectorSmartData.Temperature.Current, + } + + tags, fields := smartTemp.Flatten() + tags["device_wwn"] = wwn + p := influxdb2.NewPoint("temp", + tags, + fields, + smartTemp.Date) + return sr.influxWriteApi.WritePoint(ctx, p) + } + return nil +} + +func (sr *scrutinyRepository) GetSmartTemperatureHistory(ctx context.Context) (map[string][]measurements.SmartTemperature, error) { + + deviceTempHistory := map[string][]measurements.SmartTemperature{} + + //TODO: change the query range to a variable. + queryStr := fmt.Sprintf(` + import "influxdata/influxdb/schema" + from(bucket: "%s") + |> range(start: -3y, stop: now()) + |> filter(fn: (r) => r["_measurement"] == "temp" ) + |> filter(fn: (r) => r["_field"] == "temp") + |> schema.fieldsAsCols() + |> group(columns: ["device_wwn"]) + |> yield(name: "last") + `, + sr.appConfig.GetString("web.influxdb.bucket"), + ) + + result, err := sr.influxQueryApi.Query(ctx, queryStr) + if err == nil { + // Use Next() to iterate over query result lines + for result.Next() { + + if deviceWWN, ok := result.Record().Values()["device_wwn"]; ok { + + //check if deviceWWN has been seen and initialized already + if _, ok := deviceTempHistory[deviceWWN.(string)]; !ok { + deviceTempHistory[deviceWWN.(string)] = []measurements.SmartTemperature{} + } + + currentTempHistory := deviceTempHistory[deviceWWN.(string)] + smartTemp := measurements.SmartTemperature{} + + for key, val := range result.Record().Values() { + smartTemp.Inflate(key, val) + } + smartTemp.Date = result.Record().Values()["_time"].(time.Time) + currentTempHistory = append(currentTempHistory, smartTemp) + deviceTempHistory[deviceWWN.(string)] = currentTempHistory + } + } + if result.Err() != nil { + fmt.Printf("Query error: %s\n", result.Err().Error()) + } + } else { + return nil, err + } + return deviceTempHistory, nil + +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// DeviceSummary +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// get a map of all devices and associated SMART data +func (sr *scrutinyRepository) GetSummary(ctx context.Context) (map[string]*models.DeviceSummary, error) { + devices, err := sr.GetDevices(ctx) + if err != nil { + return nil, err + } + + summaries := map[string]*models.DeviceSummary{} + + for _, device := range devices { + summaries[device.WWN] = &models.DeviceSummary{Device: device} + } + + // Get parser flux query result + //appConfig.GetString("web.influxdb.bucket") + queryStr := fmt.Sprintf(` + import "influxdata/influxdb/schema" + from(bucket: "%s") + |> range(start: -1y, stop: now()) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> filter(fn: (r) => r["_field"] == "temp" or r["_field"] == "power_on_hours" or r["_field"] == "date") + |> schema.fieldsAsCols() + |> group(columns: ["device_wwn"]) + |> yield(name: "last") + `, + sr.appConfig.GetString("web.influxdb.bucket"), + ) + + result, err := sr.influxQueryApi.Query(ctx, queryStr) + if err == nil { + // Use Next() to iterate over query result lines + for result.Next() { + // Observe when there is new grouping key producing new table + if result.TableChanged() { + //fmt.Printf("table: %s\n", result.TableMetadata().String()) + } + // read result + + //get summary data from Influxdb. + //result.Record().Values() + if deviceWWN, ok := result.Record().Values()["device_wwn"]; ok { + summaries[deviceWWN.(string)].SmartResults = &models.SmartSummary{ + Temp: result.Record().Values()["temp"].(int64), + PowerOnHours: result.Record().Values()["power_on_hours"].(int64), + CollectorDate: result.Record().Values()["_time"].(time.Time), + } + } + } + if result.Err() != nil { + fmt.Printf("Query error: %s\n", result.Err().Error()) + } + } else { + return nil, err + } + + deviceTempHistory, err := sr.GetSmartTemperatureHistory(ctx) + if err != nil { + sr.logger.Printf("========================>>>>>>>>======================") + sr.logger.Printf("========================>>>>>>>>======================") + sr.logger.Printf("========================>>>>>>>>======================") + sr.logger.Printf("========================>>>>>>>>======================") + sr.logger.Printf("========================>>>>>>>>======================") + sr.logger.Printf("Error: %v", err) + } + for wwn, tempHistory := range deviceTempHistory { + summaries[wwn].TempHistory = tempHistory + } + + return summaries, nil +} diff --git a/webapp/backend/pkg/metadata/ata_attribute_metadata.go b/webapp/backend/pkg/metadata/ata_attribute_metadata.go index 63dc293..2f4c6c8 100644 --- a/webapp/backend/pkg/metadata/ata_attribute_metadata.go +++ b/webapp/backend/pkg/metadata/ata_attribute_metadata.go @@ -11,10 +11,10 @@ type AtaAttributeMetadata struct { Critical bool `json:"critical"` Description string `json:"description"` - Transform func(int, int64, string) int64 `json:"-"` //this should be a method to extract/tranform the normalized or raw data to a chartable format. Str - TransformValueUnit string `json:"transform_value_unit,omitempty"` - ObservedThresholds []ObservedThreshold `json:"observed_thresholds,omitempty"` //these thresholds must match the DisplayType - DisplayType string `json:"display_type"` //"raw" "normalized" or "transformed" + Transform func(int64, int64, string) int64 `json:"-"` //this should be a method to extract/tranform the normalized or raw data to a chartable format. Str + TransformValueUnit string `json:"transform_value_unit,omitempty"` + ObservedThresholds []ObservedThreshold `json:"observed_thresholds,omitempty"` //these thresholds must match the DisplayType + DisplayType string `json:"display_type"` //"raw" "normalized" or "transformed" } const ObservedThresholdIdealLow = "low" @@ -1014,7 +1014,7 @@ var AtaMetadata = map[int]AtaAttributeMetadata{ Ideal: ObservedThresholdIdealLow, Critical: false, Description: "Indicates the device temperature, if the appropriate sensor is fitted. Lowest byte of the raw value contains the exact temperature value (Celsius degrees).", - Transform: func(normValue int, rawValue int64, rawString string) int64 { + Transform: func(normValue int64, rawValue int64, rawString string) int64 { return rawValue & 0b11111111 }, TransformValueUnit: "°C", diff --git a/webapp/backend/pkg/metadata/nvme_attribute_metadata.go b/webapp/backend/pkg/metadata/nvme_attribute_metadata.go index 2f9f550..80efcfa 100644 --- a/webapp/backend/pkg/metadata/nvme_attribute_metadata.go +++ b/webapp/backend/pkg/metadata/nvme_attribute_metadata.go @@ -11,9 +11,9 @@ type NvmeAttributeMetadata struct { Critical bool `json:"critical"` Description string `json:"description"` - Transform func(int, int64, string) int64 `json:"-"` //this should be a method to extract/tranform the normalized or raw data to a chartable format. Str - TransformValueUnit string `json:"transform_value_unit,omitempty"` - DisplayType string `json:"display_type"` //"raw" "normalized" or "transformed" + Transform func(int64, int64, string) int64 `json:"-"` //this should be a method to extract/tranform the normalized or raw data to a chartable format. Str + TransformValueUnit string `json:"transform_value_unit,omitempty"` + DisplayType string `json:"display_type"` //"raw" "normalized" or "transformed" } var NmveMetadata = map[string]NvmeAttributeMetadata{ diff --git a/webapp/backend/pkg/metadata/scsi_attribute_metadata.go b/webapp/backend/pkg/metadata/scsi_attribute_metadata.go index 5e83f2a..cd4f974 100644 --- a/webapp/backend/pkg/metadata/scsi_attribute_metadata.go +++ b/webapp/backend/pkg/metadata/scsi_attribute_metadata.go @@ -7,9 +7,9 @@ type ScsiAttributeMetadata struct { Critical bool `json:"critical"` Description string `json:"description"` - Transform func(int, int64, string) int64 `json:"-"` //this should be a method to extract/tranform the normalized or raw data to a chartable format. Str - TransformValueUnit string `json:"transform_value_unit,omitempty"` - DisplayType string `json:"display_type"` //"raw" "normalized" or "transformed" + Transform func(int64, int64, string) int64 `json:"-"` //this should be a method to extract/tranform the normalized or raw data to a chartable format. Str + TransformValueUnit string `json:"transform_value_unit,omitempty"` + DisplayType string `json:"display_type"` //"raw" "normalized" or "transformed" } var ScsiMetadata = map[string]ScsiAttributeMetadata{ @@ -21,96 +21,96 @@ var ScsiMetadata = map[string]ScsiAttributeMetadata{ Critical: true, Description: "", }, - "read.errors_corrected_by_eccfast": { - ID: "read.errors_corrected_by_eccfast", + "read_errors_corrected_by_eccfast": { + ID: "read_errors_corrected_by_eccfast", DisplayName: "Read Errors Corrected by ECC Fast", DisplayType: "", Ideal: "", Critical: false, Description: "", }, - "read.errors_corrected_by_eccdelayed": { - ID: "read.errors_corrected_by_eccdelayed", + "read_errors_corrected_by_eccdelayed": { + ID: "read_errors_corrected_by_eccdelayed", DisplayName: "Read Errors Corrected by ECC Delayed", DisplayType: "", Ideal: "", Critical: false, Description: "", }, - "read.errors_corrected_by_rereads_rewrites": { - ID: "read.errors_corrected_by_rereads_rewrites", + "read_errors_corrected_by_rereads_rewrites": { + ID: "read_errors_corrected_by_rereads_rewrites", DisplayName: "Read Errors Corrected by ReReads/ReWrites", DisplayType: "", Ideal: "low", Critical: true, Description: "", }, - "read.total_errors_corrected": { - ID: "read.total_errors_corrected", + "read_total_errors_corrected": { + ID: "read_total_errors_corrected", DisplayName: "Read Total Errors Corrected", DisplayType: "", Ideal: "", Critical: false, Description: "", }, - "read.correction_algorithm_invocations": { - ID: "read.correction_algorithm_invocations", + "read_correction_algorithm_invocations": { + ID: "read_correction_algorithm_invocations", DisplayName: "Read Correction Algorithm Invocations", DisplayType: "", Ideal: "", Critical: false, Description: "", }, - "read.total_uncorrected_errors": { - ID: "read.total_uncorrected_errors", + "read_total_uncorrected_errors": { + ID: "read_total_uncorrected_errors", DisplayName: "Read Total Uncorrected Errors", DisplayType: "", Ideal: "low", Critical: true, Description: "", }, - "write.errors_corrected_by_eccfast": { - ID: "write.errors_corrected_by_eccfast", + "write_errors_corrected_by_eccfast": { + ID: "write_errors_corrected_by_eccfast", DisplayName: "Write Errors Corrected by ECC Fast", DisplayType: "", Ideal: "", Critical: false, Description: "", }, - "write.errors_corrected_by_eccdelayed": { - ID: "write.errors_corrected_by_eccdelayed", + "write_errors_corrected_by_eccdelayed": { + ID: "write_errors_corrected_by_eccdelayed", DisplayName: "Write Errors Corrected by ECC Delayed", DisplayType: "", Ideal: "", Critical: false, Description: "", }, - "write.errors_corrected_by_rereads_rewrites": { - ID: "write.errors_corrected_by_rereads_rewrites", + "write_errors_corrected_by_rereads_rewrites": { + ID: "write_errors_corrected_by_rereads_rewrites", DisplayName: "Write Errors Corrected by ReReads/ReWrites", DisplayType: "", Ideal: "low", Critical: true, Description: "", }, - "write.total_errors_corrected": { - ID: "write.total_errors_corrected", + "write_total_errors_corrected": { + ID: "write_total_errors_corrected", DisplayName: "Write Total Errors Corrected", DisplayType: "", Ideal: "", Critical: false, Description: "", }, - "write.correction_algorithm_invocations": { - ID: "write.correction_algorithm_invocations", + "write_correction_algorithm_invocations": { + ID: "write_correction_algorithm_invocations", DisplayName: "Write Correction Algorithm Invocations", DisplayType: "", Ideal: "", Critical: false, Description: "", }, - "write.total_uncorrected_errors": { - ID: "write.total_uncorrected_errors", + "write_total_uncorrected_errors": { + ID: "write_total_uncorrected_errors", DisplayName: "Write Total Uncorrected Errors", DisplayType: "", Ideal: "low", diff --git a/webapp/backend/pkg/models/collector/smart.go b/webapp/backend/pkg/models/collector/smart.go index 04d5e4c..8cb5653 100644 --- a/webapp/backend/pkg/models/collector/smart.go +++ b/webapp/backend/pkg/models/collector/smart.go @@ -119,14 +119,28 @@ type SmartInfo struct { FeatureControlSupported bool `json:"feature_control_supported"` DataTableSupported bool `json:"data_table_supported"` } `json:"ata_sct_capabilities"` + AtaSctTemperatureHistory struct { + Version int `json:"version"` + SamplingPeriodMinutes int64 `json:"sampling_period_minutes"` + LoggingIntervalMinutes int64 `json:"logging_interval_minutes"` + Temperature struct { + OpLimitMin int `json:"op_limit_min"` + OpLimitMax int `json:"op_limit_max"` + LimitMin int `json:"limit_min"` + LimitMax int `json:"limit_max"` + } `json:"temperature"` + Size int `json:"size"` + Index int `json:"index"` + Table []int64 `json:"table"` + } `json:"ata_sct_temperature_history"` AtaSmartAttributes struct { Revision int `json:"revision"` Table []struct { ID int `json:"id"` Name string `json:"name"` - Value int `json:"value"` - Worst int `json:"worst"` - Thresh int `json:"thresh"` + Value int64 `json:"value"` + Worst int64 `json:"worst"` + Thresh int64 `json:"thresh"` WhenFailed string `json:"when_failed"` Flags struct { Value int `json:"value"` @@ -237,48 +251,48 @@ type SmartInfo struct { FormattedLbaSize int `json:"formatted_lba_size"` } `json:"nvme_namespaces"` NvmeSmartHealthInformationLog struct { - CriticalWarning int `json:"critical_warning"` - Temperature int `json:"temperature"` - AvailableSpare int `json:"available_spare"` - AvailableSpareThreshold int `json:"available_spare_threshold"` - PercentageUsed int `json:"percentage_used"` - DataUnitsRead int `json:"data_units_read"` - DataUnitsWritten int `json:"data_units_written"` - HostReads int `json:"host_reads"` - HostWrites int `json:"host_writes"` - ControllerBusyTime int `json:"controller_busy_time"` - PowerCycles int `json:"power_cycles"` - PowerOnHours int `json:"power_on_hours"` - UnsafeShutdowns int `json:"unsafe_shutdowns"` - MediaErrors int `json:"media_errors"` - NumErrLogEntries int `json:"num_err_log_entries"` - WarningTempTime int `json:"warning_temp_time"` - CriticalCompTime int `json:"critical_comp_time"` + CriticalWarning int64 `json:"critical_warning"` + Temperature int64 `json:"temperature"` + AvailableSpare int64 `json:"available_spare"` + AvailableSpareThreshold int64 `json:"available_spare_threshold"` + PercentageUsed int64 `json:"percentage_used"` + DataUnitsRead int64 `json:"data_units_read"` + DataUnitsWritten int64 `json:"data_units_written"` + HostReads int64 `json:"host_reads"` + HostWrites int64 `json:"host_writes"` + ControllerBusyTime int64 `json:"controller_busy_time"` + PowerCycles int64 `json:"power_cycles"` + PowerOnHours int64 `json:"power_on_hours"` + UnsafeShutdowns int64 `json:"unsafe_shutdowns"` + MediaErrors int64 `json:"media_errors"` + NumErrLogEntries int64 `json:"num_err_log_entries"` + WarningTempTime int64 `json:"warning_temp_time"` + CriticalCompTime int64 `json:"critical_comp_time"` } `json:"nvme_smart_health_information_log"` // SCSI Protocol Specific Fields Vendor string `json:"vendor"` Product string `json:"product"` ScsiVersion string `json:"scsi_version"` - ScsiGrownDefectList int `json:"scsi_grown_defect_list"` + ScsiGrownDefectList int64 `json:"scsi_grown_defect_list"` ScsiErrorCounterLog struct { Read struct { - ErrorsCorrectedByEccfast int `json:"errors_corrected_by_eccfast"` - ErrorsCorrectedByEccdelayed int `json:"errors_corrected_by_eccdelayed"` - ErrorsCorrectedByRereadsRewrites int `json:"errors_corrected_by_rereads_rewrites"` - TotalErrorsCorrected int `json:"total_errors_corrected"` - CorrectionAlgorithmInvocations int `json:"correction_algorithm_invocations"` + ErrorsCorrectedByEccfast int64 `json:"errors_corrected_by_eccfast"` + ErrorsCorrectedByEccdelayed int64 `json:"errors_corrected_by_eccdelayed"` + ErrorsCorrectedByRereadsRewrites int64 `json:"errors_corrected_by_rereads_rewrites"` + TotalErrorsCorrected int64 `json:"total_errors_corrected"` + CorrectionAlgorithmInvocations int64 `json:"correction_algorithm_invocations"` GigabytesProcessed string `json:"gigabytes_processed"` - TotalUncorrectedErrors int `json:"total_uncorrected_errors"` + TotalUncorrectedErrors int64 `json:"total_uncorrected_errors"` } `json:"read"` Write struct { - ErrorsCorrectedByEccfast int `json:"errors_corrected_by_eccfast"` - ErrorsCorrectedByEccdelayed int `json:"errors_corrected_by_eccdelayed"` - ErrorsCorrectedByRereadsRewrites int `json:"errors_corrected_by_rereads_rewrites"` - TotalErrorsCorrected int `json:"total_errors_corrected"` - CorrectionAlgorithmInvocations int `json:"correction_algorithm_invocations"` + ErrorsCorrectedByEccfast int64 `json:"errors_corrected_by_eccfast"` + ErrorsCorrectedByEccdelayed int64 `json:"errors_corrected_by_eccdelayed"` + ErrorsCorrectedByRereadsRewrites int64 `json:"errors_corrected_by_rereads_rewrites"` + TotalErrorsCorrected int64 `json:"total_errors_corrected"` + CorrectionAlgorithmInvocations int64 `json:"correction_algorithm_invocations"` GigabytesProcessed string `json:"gigabytes_processed"` - TotalUncorrectedErrors int `json:"total_uncorrected_errors"` + TotalUncorrectedErrors int64 `json:"total_uncorrected_errors"` } `json:"write"` } `json:"scsi_error_counter_log"` } diff --git a/webapp/backend/pkg/models/db/device.go b/webapp/backend/pkg/models/db/device.go deleted file mode 100644 index 2786103..0000000 --- a/webapp/backend/pkg/models/db/device.go +++ /dev/null @@ -1,160 +0,0 @@ -package db - -import ( - "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" - "time" -) - -type DeviceWrapper struct { - Success bool `json:"success"` - Errors []error `json:"errors"` - Data []Device `json:"data"` -} - -const DeviceProtocolAta = "ATA" -const DeviceProtocolScsi = "SCSI" -const DeviceProtocolNvme = "NVMe" - -type Device struct { - //GORM attributes, see: http://gorm.io/docs/conventions.html - CreatedAt time.Time - UpdatedAt time.Time - DeletedAt *time.Time - - WWN string `json:"wwn" gorm:"primary_key"` - HostId string `json:"host_id"` - - DeviceName string `json:"device_name"` - Manufacturer string `json:"manufacturer"` - ModelName string `json:"model_name"` - InterfaceType string `json:"interface_type"` - InterfaceSpeed string `json:"interface_speed"` - SerialNumber string `json:"serial_number"` - Firmware string `json:"firmware"` - RotationSpeed int `json:"rotational_speed"` - Capacity int64 `json:"capacity"` - FormFactor string `json:"form_factor"` - SmartSupport bool `json:"smart_support"` - DeviceProtocol string `json:"device_protocol"` //protocol determines which smart attribute types are available (ATA, NVMe, SCSI) - DeviceType string `json:"device_type"` //device type is used for querying with -d/t flag, should only be used by collector. - SmartResults []Smart `gorm:"foreignkey:DeviceWWN" json:"smart_results"` -} - -func (dv *Device) IsAta() bool { - return dv.DeviceProtocol == DeviceProtocolAta -} - -func (dv *Device) IsScsi() bool { - return dv.DeviceProtocol == DeviceProtocolScsi -} - -func (dv *Device) IsNvme() bool { - return dv.DeviceProtocol == DeviceProtocolNvme -} - -//This method requires a device with an array of SmartResults. -//It will remove all SmartResults other than the first (the latest one) -//All removed SmartResults, will be processed, grouping SmartAtaAttribute by attribute_id -// and adding theme to an array called History. -func (dv *Device) SquashHistory() error { - if len(dv.SmartResults) <= 1 { - return nil //no ataHistory found. ignore - } - - latestSmartResultSlice := dv.SmartResults[0:1] - historicalSmartResultSlice := dv.SmartResults[1:] - - //re-assign the latest slice to the SmartResults field - dv.SmartResults = latestSmartResultSlice - - //process the historical slice for ATA data - if len(dv.SmartResults[0].AtaAttributes) > 0 { - ataHistory := map[int][]SmartAtaAttribute{} - for _, smartResult := range historicalSmartResultSlice { - for _, smartAttribute := range smartResult.AtaAttributes { - if _, ok := ataHistory[smartAttribute.AttributeId]; !ok { - ataHistory[smartAttribute.AttributeId] = []SmartAtaAttribute{} - } - ataHistory[smartAttribute.AttributeId] = append(ataHistory[smartAttribute.AttributeId], smartAttribute) - } - } - - //now assign the historical slices to the AtaAttributes in the latest SmartResults - for sandx, smartAttribute := range dv.SmartResults[0].AtaAttributes { - if attributeHistory, ok := ataHistory[smartAttribute.AttributeId]; ok { - dv.SmartResults[0].AtaAttributes[sandx].History = attributeHistory - } - } - } - - //process the historical slice for Nvme data - if len(dv.SmartResults[0].NvmeAttributes) > 0 { - nvmeHistory := map[string][]SmartNvmeAttribute{} - for _, smartResult := range historicalSmartResultSlice { - for _, smartAttribute := range smartResult.NvmeAttributes { - if _, ok := nvmeHistory[smartAttribute.AttributeId]; !ok { - nvmeHistory[smartAttribute.AttributeId] = []SmartNvmeAttribute{} - } - nvmeHistory[smartAttribute.AttributeId] = append(nvmeHistory[smartAttribute.AttributeId], smartAttribute) - } - } - - //now assign the historical slices to the AtaAttributes in the latest SmartResults - for sandx, smartAttribute := range dv.SmartResults[0].NvmeAttributes { - if attributeHistory, ok := nvmeHistory[smartAttribute.AttributeId]; ok { - dv.SmartResults[0].NvmeAttributes[sandx].History = attributeHistory - } - } - } - //process the historical slice for Scsi data - if len(dv.SmartResults[0].ScsiAttributes) > 0 { - scsiHistory := map[string][]SmartScsiAttribute{} - for _, smartResult := range historicalSmartResultSlice { - for _, smartAttribute := range smartResult.ScsiAttributes { - if _, ok := scsiHistory[smartAttribute.AttributeId]; !ok { - scsiHistory[smartAttribute.AttributeId] = []SmartScsiAttribute{} - } - scsiHistory[smartAttribute.AttributeId] = append(scsiHistory[smartAttribute.AttributeId], smartAttribute) - } - } - - //now assign the historical slices to the AtaAttributes in the latest SmartResults - for sandx, smartAttribute := range dv.SmartResults[0].ScsiAttributes { - if attributeHistory, ok := scsiHistory[smartAttribute.AttributeId]; ok { - dv.SmartResults[0].ScsiAttributes[sandx].History = attributeHistory - } - } - } - return nil -} - -func (dv *Device) ApplyMetadataRules() error { - - //embed metadata in the latest smart attributes object - if len(dv.SmartResults) > 0 { - for ndx, attr := range dv.SmartResults[0].AtaAttributes { - attr.PopulateAttributeStatus() - dv.SmartResults[0].AtaAttributes[ndx] = attr - } - - for ndx, attr := range dv.SmartResults[0].NvmeAttributes { - attr.PopulateAttributeStatus() - dv.SmartResults[0].NvmeAttributes[ndx] = attr - - } - - for ndx, attr := range dv.SmartResults[0].ScsiAttributes { - attr.PopulateAttributeStatus() - dv.SmartResults[0].ScsiAttributes[ndx] = attr - - } - } - return nil -} - -// This function is called every time the collector sends SMART data to the API. -// It can be used to update device data that can change over time. -func (dv *Device) UpdateFromCollectorSmartInfo(info collector.SmartInfo) error { - dv.Firmware = info.FirmwareVersion - return nil -} diff --git a/webapp/backend/pkg/models/db/selftest.go b/webapp/backend/pkg/models/db/selftest.go deleted file mode 100644 index 9e3d89d..0000000 --- a/webapp/backend/pkg/models/db/selftest.go +++ /dev/null @@ -1,15 +0,0 @@ -package db - -import "time" - -type SelfTest struct { - //GORM attributes, see: http://gorm.io/docs/conventions.html - CreatedAt time.Time - UpdatedAt time.Time - DeletedAt *time.Time - - DeviceWWN string - Device Device `json:"-" gorm:"foreignkey:DeviceWWN"` // use DeviceWWN as foreign key - - Date time.Time -} diff --git a/webapp/backend/pkg/models/db/smart.go b/webapp/backend/pkg/models/db/smart.go deleted file mode 100644 index 510dcb2..0000000 --- a/webapp/backend/pkg/models/db/smart.go +++ /dev/null @@ -1,127 +0,0 @@ -package db - -import ( - "github.com/analogj/scrutiny/webapp/backend/pkg/metadata" - "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" - "gorm.io/gorm" - "time" -) - -const SmartWhenFailedFailingNow = "FAILING_NOW" -const SmartWhenFailedInThePast = "IN_THE_PAST" - -const SmartStatusPassed = "passed" -const SmartStatusFailed = "failed" - -type Smart struct { - gorm.Model - - DeviceWWN string `json:"device_wwn"` - Device Device `json:"-" gorm:"foreignkey:DeviceWWN"` // use DeviceWWN as foreign key - - TestDate time.Time `json:"date"` - SmartStatus string `json:"smart_status"` // SmartStatusPassed or SmartStatusFailed - - //Metrics - Temp int64 `json:"temp"` - PowerOnHours int64 `json:"power_on_hours"` - PowerCycleCount int64 `json:"power_cycle_count"` - - AtaAttributes []SmartAtaAttribute `json:"ata_attributes" gorm:"foreignkey:SmartId"` - NvmeAttributes []SmartNvmeAttribute `json:"nvme_attributes" gorm:"foreignkey:SmartId"` - ScsiAttributes []SmartScsiAttribute `json:"scsi_attributes" gorm:"foreignkey:SmartId"` -} - -//Parse Collector SMART data results and create Smart object (and associated SmartAtaAttribute entries) -func (sm *Smart) FromCollectorSmartInfo(wwn string, info collector.SmartInfo) error { - sm.DeviceWWN = wwn - sm.TestDate = time.Unix(info.LocalTime.TimeT, 0) - - //smart metrics - sm.Temp = info.Temperature.Current - sm.PowerCycleCount = info.PowerCycleCount - sm.PowerOnHours = info.PowerOnTime.Hours - - // process ATA/NVME/SCSI protocol data - if info.Device.Protocol == DeviceProtocolAta { - sm.ProcessAtaSmartInfo(info) - } else if info.Device.Protocol == DeviceProtocolNvme { - sm.ProcessNvmeSmartInfo(info) - } else if info.Device.Protocol == DeviceProtocolScsi { - sm.ProcessScsiSmartInfo(info) - } - - if info.SmartStatus.Passed { - sm.SmartStatus = SmartStatusPassed - } else { - sm.SmartStatus = SmartStatusFailed - } - return nil -} - -//generate SmartAtaAttribute entries from Scrutiny Collector Smart data. -func (sm *Smart) ProcessAtaSmartInfo(info collector.SmartInfo) { - sm.AtaAttributes = []SmartAtaAttribute{} - for _, collectorAttr := range info.AtaSmartAttributes.Table { - attrModel := SmartAtaAttribute{ - AttributeId: collectorAttr.ID, - Name: collectorAttr.Name, - Value: collectorAttr.Value, - Worst: collectorAttr.Worst, - Threshold: collectorAttr.Thresh, - RawValue: collectorAttr.Raw.Value, - RawString: collectorAttr.Raw.String, - WhenFailed: collectorAttr.WhenFailed, - } - - //now that we've parsed the data from the smartctl response, lets match it against our metadata rules and add additional Scrutiny specific data. - if smartMetadata, ok := metadata.AtaMetadata[collectorAttr.ID]; ok { - attrModel.Name = smartMetadata.DisplayName - if smartMetadata.Transform != nil { - attrModel.TransformedValue = smartMetadata.Transform(attrModel.Value, attrModel.RawValue, attrModel.RawString) - } - } - sm.AtaAttributes = append(sm.AtaAttributes, attrModel) - } -} - -//generate SmartNvmeAttribute entries from Scrutiny Collector Smart data. -func (sm *Smart) ProcessNvmeSmartInfo(info collector.SmartInfo) { - sm.NvmeAttributes = []SmartNvmeAttribute{ - {AttributeId: "critical_warning", Name: "Critical Warning", Value: info.NvmeSmartHealthInformationLog.CriticalWarning, Threshold: 0}, - {AttributeId: "temperature", Name: "Temperature", Value: info.NvmeSmartHealthInformationLog.Temperature, Threshold: -1}, - {AttributeId: "available_spare", Name: "Available Spare", Value: info.NvmeSmartHealthInformationLog.AvailableSpare, Threshold: info.NvmeSmartHealthInformationLog.AvailableSpareThreshold}, - {AttributeId: "percentage_used", Name: "Percentage Used", Value: info.NvmeSmartHealthInformationLog.PercentageUsed, Threshold: 100}, - {AttributeId: "data_units_read", Name: "Data Units Read", Value: info.NvmeSmartHealthInformationLog.DataUnitsRead, Threshold: -1}, - {AttributeId: "data_units_written", Name: "Data Units Written", Value: info.NvmeSmartHealthInformationLog.DataUnitsWritten, Threshold: -1}, - {AttributeId: "host_reads", Name: "Host Reads", Value: info.NvmeSmartHealthInformationLog.HostReads, Threshold: -1}, - {AttributeId: "host_writes", Name: "Host Writes", Value: info.NvmeSmartHealthInformationLog.HostWrites, Threshold: -1}, - {AttributeId: "controller_busy_time", Name: "Controller Busy Time", Value: info.NvmeSmartHealthInformationLog.ControllerBusyTime, Threshold: -1}, - {AttributeId: "power_cycles", Name: "Power Cycles", Value: info.NvmeSmartHealthInformationLog.PowerCycles, Threshold: -1}, - {AttributeId: "power_on_hours", Name: "Power on Hours", Value: info.NvmeSmartHealthInformationLog.PowerOnHours, Threshold: -1}, - {AttributeId: "unsafe_shutdowns", Name: "Unsafe Shutdowns", Value: info.NvmeSmartHealthInformationLog.UnsafeShutdowns, Threshold: -1}, - {AttributeId: "media_errors", Name: "Media Errors", Value: info.NvmeSmartHealthInformationLog.MediaErrors, Threshold: 0}, - {AttributeId: "num_err_log_entries", Name: "Numb Err Log Entries", Value: info.NvmeSmartHealthInformationLog.NumErrLogEntries, Threshold: 0}, - {AttributeId: "warning_temp_time", Name: "Warning Temp Time", Value: info.NvmeSmartHealthInformationLog.WarningTempTime, Threshold: -1}, - {AttributeId: "critical_comp_time", Name: "Critical CompTime", Value: info.NvmeSmartHealthInformationLog.CriticalCompTime, Threshold: -1}, - } -} - -//generate SmartScsiAttribute entries from Scrutiny Collector Smart data. -func (sm *Smart) ProcessScsiSmartInfo(info collector.SmartInfo) { - sm.ScsiAttributes = []SmartScsiAttribute{ - {AttributeId: "scsi_grown_defect_list", Name: "Grown Defect List", Value: info.ScsiGrownDefectList, Threshold: 0}, - {AttributeId: "read.errors_corrected_by_eccfast", Name: "Read Errors Corrected by ECC Fast", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccfast, Threshold: -1}, - {AttributeId: "read.errors_corrected_by_eccdelayed", Name: "Read Errors Corrected by ECC Delayed", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccdelayed, Threshold: -1}, - {AttributeId: "read.errors_corrected_by_rereads_rewrites", Name: "Read Errors Corrected by ReReads/ReWrites", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByRereadsRewrites, Threshold: 0}, - {AttributeId: "read.total_errors_corrected", Name: "Read Total Errors Corrected", Value: info.ScsiErrorCounterLog.Read.TotalErrorsCorrected, Threshold: -1}, - {AttributeId: "read.correction_algorithm_invocations", Name: "Read Correction Algorithm Invocations", Value: info.ScsiErrorCounterLog.Read.CorrectionAlgorithmInvocations, Threshold: -1}, - {AttributeId: "read.total_uncorrected_errors", Name: "Read Total Uncorrected Errors", Value: info.ScsiErrorCounterLog.Read.TotalUncorrectedErrors, Threshold: 0}, - {AttributeId: "write.errors_corrected_by_eccfast", Name: "Write Errors Corrected by ECC Fast", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccfast, Threshold: -1}, - {AttributeId: "write.errors_corrected_by_eccdelayed", Name: "Write Errors Corrected by ECC Delayed", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccdelayed, Threshold: -1}, - {AttributeId: "write.errors_corrected_by_rereads_rewrites", Name: "Write Errors Corrected by ReReads/ReWrites", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByRereadsRewrites, Threshold: 0}, - {AttributeId: "write.total_errors_corrected", Name: "Write Total Errors Corrected", Value: info.ScsiErrorCounterLog.Write.TotalErrorsCorrected, Threshold: -1}, - {AttributeId: "write.correction_algorithm_invocations", Name: "Write Correction Algorithm Invocations", Value: info.ScsiErrorCounterLog.Write.CorrectionAlgorithmInvocations, Threshold: -1}, - {AttributeId: "write.total_uncorrected_errors", Name: "Write Total Uncorrected Errors", Value: info.ScsiErrorCounterLog.Write.TotalUncorrectedErrors, Threshold: 0}, - } -} diff --git a/webapp/backend/pkg/models/db/smart_ata_attribute.go b/webapp/backend/pkg/models/db/smart_ata_attribute.go deleted file mode 100644 index 510672d..0000000 --- a/webapp/backend/pkg/models/db/smart_ata_attribute.go +++ /dev/null @@ -1,111 +0,0 @@ -package db - -import ( - "github.com/analogj/scrutiny/webapp/backend/pkg/metadata" - "gorm.io/gorm" - "strings" -) - -const SmartAttributeStatusPassed = "passed" -const SmartAttributeStatusFailed = "failed" -const SmartAttributeStatusWarning = "warn" - -type SmartAtaAttribute struct { - gorm.Model - - SmartId int `json:"smart_id"` - Smart Device `json:"-" gorm:"foreignkey:SmartId"` // use SmartId as foreign key - - AttributeId int `json:"attribute_id"` - Name string `json:"name"` - Value int `json:"value"` - Worst int `json:"worst"` - Threshold int `json:"thresh"` - RawValue int64 `json:"raw_value"` - RawString string `json:"raw_string"` - WhenFailed string `json:"when_failed"` - - TransformedValue int64 `json:"transformed_value"` - Status string `gorm:"-" json:"status,omitempty"` - StatusReason string `gorm:"-" json:"status_reason,omitempty"` - FailureRate float64 `gorm:"-" json:"failure_rate,omitempty"` - History []SmartAtaAttribute `gorm:"-" json:"history,omitempty"` -} - -//populate attribute status, using SMART Thresholds & Observed Metadata -func (sa *SmartAtaAttribute) PopulateAttributeStatus() { - if strings.ToUpper(sa.WhenFailed) == SmartWhenFailedFailingNow { - //this attribute has previously failed - sa.Status = SmartAttributeStatusFailed - sa.StatusReason = "Attribute is failing manufacturer SMART threshold" - - } else if strings.ToUpper(sa.WhenFailed) == SmartWhenFailedInThePast { - sa.Status = SmartAttributeStatusWarning - sa.StatusReason = "Attribute has previously failed manufacturer SMART threshold" - } - - if smartMetadata, ok := metadata.AtaMetadata[sa.AttributeId]; ok { - sa.MetadataObservedThresholdStatus(smartMetadata) - } - - //check if status is blank, set to "passed" - if len(sa.Status) == 0 { - sa.Status = SmartAttributeStatusPassed - } -} - -// compare the attribute (raw, normalized, transformed) value to observed thresholds, and update status if necessary -func (sa *SmartAtaAttribute) MetadataObservedThresholdStatus(smartMetadata metadata.AtaAttributeMetadata) { - //TODO: multiple rules - // try to predict the failure rates for observed thresholds that have 0 failure rate and error bars. - // - if the attribute is critical - // - the failure rate is over 10 - set to failed - // - the attribute does not match any threshold, set to warn - // - if the attribute is not critical - // - if failure rate is above 20 - set to failed - // - if failure rate is above 10 but below 20 - set to warn - - //update the smart attribute status based on Observed thresholds. - var value int64 - if smartMetadata.DisplayType == metadata.AtaSmartAttributeDisplayTypeNormalized { - value = int64(sa.Value) - } else if smartMetadata.DisplayType == metadata.AtaSmartAttributeDisplayTypeTransformed { - value = sa.TransformedValue - } else { - value = sa.RawValue - } - - for _, obsThresh := range smartMetadata.ObservedThresholds { - - //check if "value" is in this bucket - if ((obsThresh.Low == obsThresh.High) && value == obsThresh.Low) || - (obsThresh.Low < value && value <= obsThresh.High) { - sa.FailureRate = obsThresh.AnnualFailureRate - - if smartMetadata.Critical { - if obsThresh.AnnualFailureRate >= 0.10 { - sa.Status = SmartAttributeStatusFailed - sa.StatusReason = "Observed Failure Rate for Critical Attribute is greater than 10%" - } - } else { - if obsThresh.AnnualFailureRate >= 0.20 { - sa.Status = SmartAttributeStatusFailed - sa.StatusReason = "Observed Failure Rate for Attribute is greater than 20%" - } else if obsThresh.AnnualFailureRate >= 0.10 { - sa.Status = SmartAttributeStatusWarning - sa.StatusReason = "Observed Failure Rate for Attribute is greater than 10%" - } - } - - //we've found the correct bucket, we can drop out of this loop - return - } - } - // no bucket found - if smartMetadata.Critical { - sa.Status = SmartAttributeStatusWarning - sa.StatusReason = "Could not determine Observed Failure Rate for Critical Attribute" - } - - return -} diff --git a/webapp/backend/pkg/models/db/smart_nvme_attribute.go b/webapp/backend/pkg/models/db/smart_nvme_attribute.go deleted file mode 100644 index b681181..0000000 --- a/webapp/backend/pkg/models/db/smart_nvme_attribute.go +++ /dev/null @@ -1,46 +0,0 @@ -package db - -import ( - "github.com/analogj/scrutiny/webapp/backend/pkg/metadata" - "gorm.io/gorm" -) - -type SmartNvmeAttribute struct { - gorm.Model - - SmartId int `json:"smart_id"` - Smart Device `json:"-" gorm:"foreignkey:SmartId"` // use SmartId as foreign key - - AttributeId string `json:"attribute_id"` //json string from smartctl - Name string `json:"name"` - Value int `json:"value"` - Threshold int `json:"thresh"` - - TransformedValue int64 `json:"transformed_value"` - Status string `gorm:"-" json:"status,omitempty"` - StatusReason string `gorm:"-" json:"status_reason,omitempty"` - FailureRate float64 `gorm:"-" json:"failure_rate,omitempty"` - History []SmartNvmeAttribute `gorm:"-" json:"history,omitempty"` -} - -//populate attribute status, using SMART Thresholds & Observed Metadata -func (sa *SmartNvmeAttribute) PopulateAttributeStatus() { - - //-1 is a special number meaning no threshold. - if sa.Threshold != -1 { - if smartMetadata, ok := metadata.NmveMetadata[sa.AttributeId]; ok { - //check what the ideal is. Ideal tells us if we our recorded value needs to be above, or below the threshold - if (smartMetadata.Ideal == "low" && sa.Value > sa.Threshold) || - (smartMetadata.Ideal == "high" && sa.Value < sa.Threshold) { - sa.Status = SmartAttributeStatusFailed - sa.StatusReason = "Attribute is failing recommended SMART threshold" - } - } - } - //TODO: eventually figure out the critical_warning bits and determine correct error messages here. - - //check if status is blank, set to "passed" - if len(sa.Status) == 0 { - sa.Status = SmartAttributeStatusPassed - } -} diff --git a/webapp/backend/pkg/models/db/smart_scsci_attribute.go b/webapp/backend/pkg/models/db/smart_scsci_attribute.go deleted file mode 100644 index c6b1325..0000000 --- a/webapp/backend/pkg/models/db/smart_scsci_attribute.go +++ /dev/null @@ -1,45 +0,0 @@ -package db - -import ( - "github.com/analogj/scrutiny/webapp/backend/pkg/metadata" - "gorm.io/gorm" -) - -type SmartScsiAttribute struct { - gorm.Model - - SmartId int `json:"smart_id"` - Smart Device `json:"-" gorm:"foreignkey:SmartId"` // use SmartId as foreign key - - AttributeId string `json:"attribute_id"` //json string from smartctl - Name string `json:"name"` - Value int `json:"value"` - Threshold int `json:"thresh"` - - TransformedValue int64 `json:"transformed_value"` - Status string `gorm:"-" json:"status,omitempty"` - StatusReason string `gorm:"-" json:"status_reason,omitempty"` - FailureRate float64 `gorm:"-" json:"failure_rate,omitempty"` - History []SmartScsiAttribute `gorm:"-" json:"history,omitempty"` -} - -//populate attribute status, using SMART Thresholds & Observed Metadata -func (sa *SmartScsiAttribute) PopulateAttributeStatus() { - - //-1 is a special number meaning no threshold. - if sa.Threshold != -1 { - if smartMetadata, ok := metadata.NmveMetadata[sa.AttributeId]; ok { - //check what the ideal is. Ideal tells us if we our recorded value needs to be above, or below the threshold - if (smartMetadata.Ideal == "low" && sa.Value > sa.Threshold) || - (smartMetadata.Ideal == "high" && sa.Value < sa.Threshold) { - sa.Status = SmartAttributeStatusFailed - sa.StatusReason = "Attribute is failing recommended SMART threshold" - } - } - } - - //check if status is blank, set to "passed" - if len(sa.Status) == 0 { - sa.Status = SmartAttributeStatusPassed - } -} diff --git a/webapp/backend/pkg/models/db/smart_test.go b/webapp/backend/pkg/models/db/smart_test.go deleted file mode 100644 index 0f03715..0000000 --- a/webapp/backend/pkg/models/db/smart_test.go +++ /dev/null @@ -1,155 +0,0 @@ -package db_test - -import ( - "encoding/json" - "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" - "github.com/analogj/scrutiny/webapp/backend/pkg/models/db" - "github.com/stretchr/testify/require" - "io/ioutil" - "os" - "testing" -) - -func TestFromCollectorSmartInfo(t *testing.T) { - //setup - smartDataFile, err := os.Open("../testdata/smart-ata.json") - require.NoError(t, err) - defer smartDataFile.Close() - - var smartJson collector.SmartInfo - - smartDataBytes, err := ioutil.ReadAll(smartDataFile) - require.NoError(t, err) - err = json.Unmarshal(smartDataBytes, &smartJson) - require.NoError(t, err) - - //test - smartMdl := db.Smart{} - err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) - - //assert - require.NoError(t, err) - require.Equal(t, "WWN-test", smartMdl.DeviceWWN) - require.Equal(t, "passed", smartMdl.SmartStatus) - require.Equal(t, 18, len(smartMdl.AtaAttributes)) - require.Equal(t, 0, len(smartMdl.NvmeAttributes)) - require.Equal(t, 0, len(smartMdl.ScsiAttributes)) - - //check that temperature was correctly parsed - for _, attr := range smartMdl.AtaAttributes { - if attr.AttributeId == 194 { - require.Equal(t, int64(163210330144), attr.RawValue) - require.Equal(t, int64(32), attr.TransformedValue) - } - } -} - -func TestFromCollectorSmartInfo_Fail(t *testing.T) { - //setup - smartDataFile, err := os.Open("../testdata/smart-fail.json") - require.NoError(t, err) - defer smartDataFile.Close() - - var smartJson collector.SmartInfo - - smartDataBytes, err := ioutil.ReadAll(smartDataFile) - require.NoError(t, err) - err = json.Unmarshal(smartDataBytes, &smartJson) - require.NoError(t, err) - - //test - smartMdl := db.Smart{} - err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) - - //assert - require.NoError(t, err) - require.Equal(t, "WWN-test", smartMdl.DeviceWWN) - require.Equal(t, "failed", smartMdl.SmartStatus) - require.Equal(t, 0, len(smartMdl.AtaAttributes)) - require.Equal(t, 0, len(smartMdl.NvmeAttributes)) - require.Equal(t, 0, len(smartMdl.ScsiAttributes)) -} - -func TestFromCollectorSmartInfo_Fail2(t *testing.T) { - //setup - smartDataFile, err := os.Open("../testdata/smart-fail2.json") - require.NoError(t, err) - defer smartDataFile.Close() - - var smartJson collector.SmartInfo - - smartDataBytes, err := ioutil.ReadAll(smartDataFile) - require.NoError(t, err) - err = json.Unmarshal(smartDataBytes, &smartJson) - require.NoError(t, err) - - //test - smartMdl := db.Smart{} - err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) - - //assert - require.NoError(t, err) - require.Equal(t, "WWN-test", smartMdl.DeviceWWN) - require.Equal(t, "failed", smartMdl.SmartStatus) - require.Equal(t, 17, len(smartMdl.AtaAttributes)) - require.Equal(t, 0, len(smartMdl.NvmeAttributes)) - require.Equal(t, 0, len(smartMdl.ScsiAttributes)) -} - -func TestFromCollectorSmartInfo_Nvme(t *testing.T) { - //setup - smartDataFile, err := os.Open("../testdata/smart-nvme.json") - require.NoError(t, err) - defer smartDataFile.Close() - - var smartJson collector.SmartInfo - - smartDataBytes, err := ioutil.ReadAll(smartDataFile) - require.NoError(t, err) - err = json.Unmarshal(smartDataBytes, &smartJson) - require.NoError(t, err) - - //test - smartMdl := db.Smart{} - err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) - - //assert - require.NoError(t, err) - require.Equal(t, "WWN-test", smartMdl.DeviceWWN) - require.Equal(t, "passed", smartMdl.SmartStatus) - require.Equal(t, 0, len(smartMdl.AtaAttributes)) - require.Equal(t, 16, len(smartMdl.NvmeAttributes)) - require.Equal(t, 0, len(smartMdl.ScsiAttributes)) - - require.Equal(t, 111303174, smartMdl.NvmeAttributes[6].Value) - require.Equal(t, 83170961, smartMdl.NvmeAttributes[7].Value) -} - -func TestFromCollectorSmartInfo_Scsi(t *testing.T) { - //setup - smartDataFile, err := os.Open("../testdata/smart-scsi.json") - require.NoError(t, err) - defer smartDataFile.Close() - - var smartJson collector.SmartInfo - - smartDataBytes, err := ioutil.ReadAll(smartDataFile) - require.NoError(t, err) - err = json.Unmarshal(smartDataBytes, &smartJson) - require.NoError(t, err) - - //test - smartMdl := db.Smart{} - err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) - - //assert - require.NoError(t, err) - require.Equal(t, "WWN-test", smartMdl.DeviceWWN) - require.Equal(t, "passed", smartMdl.SmartStatus) - require.Equal(t, 0, len(smartMdl.AtaAttributes)) - require.Equal(t, 0, len(smartMdl.NvmeAttributes)) - require.Equal(t, 13, len(smartMdl.ScsiAttributes)) - - require.Equal(t, 56, smartMdl.ScsiAttributes[0].Value) - require.Equal(t, 300357663, smartMdl.ScsiAttributes[4].Value) //total_errors_corrected -} diff --git a/webapp/backend/pkg/models/device.go b/webapp/backend/pkg/models/device.go new file mode 100644 index 0000000..c5272b4 --- /dev/null +++ b/webapp/backend/pkg/models/device.go @@ -0,0 +1,169 @@ +package models + +import ( + "github.com/analogj/scrutiny/webapp/backend/pkg" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" + "time" +) + +type DeviceWrapper struct { + Success bool `json:"success"` + Errors []error `json:"errors"` + Data []Device `json:"data"` +} + +type Device struct { + //GORM attributes, see: http://gorm.io/docs/conventions.html + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt *time.Time + + WWN string `json:"wwn" gorm:"primary_key"` + + DeviceName string `json:"device_name"` + Manufacturer string `json:"manufacturer"` + ModelName string `json:"model_name"` + InterfaceType string `json:"interface_type"` + InterfaceSpeed string `json:"interface_speed"` + SerialNumber string `json:"serial_number"` + Firmware string `json:"firmware"` + RotationSpeed int `json:"rotational_speed"` + Capacity int64 `json:"capacity"` + FormFactor string `json:"form_factor"` + SmartSupport bool `json:"smart_support"` + DeviceProtocol string `json:"device_protocol"` //protocol determines which smart attribute types are available (ATA, NVMe, SCSI) + DeviceType string `json:"device_type"` //device type is used for querying with -d/t flag, should only be used by collector. + + // User provided metadata + Label string `json:"label"` + HostId string `json:"host_id"` + + // Data set by Scrutiny + DeviceStatus pkg.DeviceStatus `json:"device_status"` +} + +func (dv *Device) IsAta() bool { + return dv.DeviceProtocol == pkg.DeviceProtocolAta +} + +func (dv *Device) IsScsi() bool { + return dv.DeviceProtocol == pkg.DeviceProtocolScsi +} + +func (dv *Device) IsNvme() bool { + return dv.DeviceProtocol == pkg.DeviceProtocolNvme +} + +// +////This method requires a device with an array of SmartResults. +////It will remove all SmartResults other than the first (the latest one) +////All removed SmartResults, will be processed, grouping SmartAtaAttribute by attribute_id +//// and adding theme to an array called History. +//func (dv *Device) SquashHistory() error { +// if len(dv.SmartResults) <= 1 { +// return nil //no ataHistory found. ignore +// } +// +// latestSmartResultSlice := dv.SmartResults[0:1] +// historicalSmartResultSlice := dv.SmartResults[1:] +// +// //re-assign the latest slice to the SmartResults field +// dv.SmartResults = latestSmartResultSlice +// +// //process the historical slice for ATA data +// if len(dv.SmartResults[0].AtaAttributes) > 0 { +// ataHistory := map[int][]SmartAtaAttribute{} +// for _, smartResult := range historicalSmartResultSlice { +// for _, smartAttribute := range smartResult.AtaAttributes { +// if _, ok := ataHistory[smartAttribute.AttributeId]; !ok { +// ataHistory[smartAttribute.AttributeId] = []SmartAtaAttribute{} +// } +// ataHistory[smartAttribute.AttributeId] = append(ataHistory[smartAttribute.AttributeId], smartAttribute) +// } +// } +// +// //now assign the historical slices to the AtaAttributes in the latest SmartResults +// for sandx, smartAttribute := range dv.SmartResults[0].AtaAttributes { +// if attributeHistory, ok := ataHistory[smartAttribute.AttributeId]; ok { +// dv.SmartResults[0].AtaAttributes[sandx].History = attributeHistory +// } +// } +// } +// +// //process the historical slice for Nvme data +// if len(dv.SmartResults[0].NvmeAttributes) > 0 { +// nvmeHistory := map[string][]SmartNvmeAttribute{} +// for _, smartResult := range historicalSmartResultSlice { +// for _, smartAttribute := range smartResult.NvmeAttributes { +// if _, ok := nvmeHistory[smartAttribute.AttributeId]; !ok { +// nvmeHistory[smartAttribute.AttributeId] = []SmartNvmeAttribute{} +// } +// nvmeHistory[smartAttribute.AttributeId] = append(nvmeHistory[smartAttribute.AttributeId], smartAttribute) +// } +// } +// +// //now assign the historical slices to the AtaAttributes in the latest SmartResults +// for sandx, smartAttribute := range dv.SmartResults[0].NvmeAttributes { +// if attributeHistory, ok := nvmeHistory[smartAttribute.AttributeId]; ok { +// dv.SmartResults[0].NvmeAttributes[sandx].History = attributeHistory +// } +// } +// } +// //process the historical slice for Scsi data +// if len(dv.SmartResults[0].ScsiAttributes) > 0 { +// scsiHistory := map[string][]SmartScsiAttribute{} +// for _, smartResult := range historicalSmartResultSlice { +// for _, smartAttribute := range smartResult.ScsiAttributes { +// if _, ok := scsiHistory[smartAttribute.AttributeId]; !ok { +// scsiHistory[smartAttribute.AttributeId] = []SmartScsiAttribute{} +// } +// scsiHistory[smartAttribute.AttributeId] = append(scsiHistory[smartAttribute.AttributeId], smartAttribute) +// } +// } +// +// //now assign the historical slices to the AtaAttributes in the latest SmartResults +// for sandx, smartAttribute := range dv.SmartResults[0].ScsiAttributes { +// if attributeHistory, ok := scsiHistory[smartAttribute.AttributeId]; ok { +// dv.SmartResults[0].ScsiAttributes[sandx].History = attributeHistory +// } +// } +// } +// return nil +//} +// +//func (dv *Device) ApplyMetadataRules() error { +// +// //embed metadata in the latest smart attributes object +// if len(dv.SmartResults) > 0 { +// for ndx, attr := range dv.SmartResults[0].AtaAttributes { +// attr.PopulateAttributeStatus() +// dv.SmartResults[0].AtaAttributes[ndx] = attr +// } +// +// for ndx, attr := range dv.SmartResults[0].NvmeAttributes { +// attr.PopulateAttributeStatus() +// dv.SmartResults[0].NvmeAttributes[ndx] = attr +// +// } +// +// for ndx, attr := range dv.SmartResults[0].ScsiAttributes { +// attr.PopulateAttributeStatus() +// dv.SmartResults[0].ScsiAttributes[ndx] = attr +// +// } +// } +// return nil +//} + +// This function is called every time the collector sends SMART data to the API. +// It can be used to update device data that can change over time. +func (dv *Device) UpdateFromCollectorSmartInfo(info collector.SmartInfo) error { + dv.Firmware = info.FirmwareVersion + dv.DeviceProtocol = info.Device.Protocol + + if !info.SmartStatus.Passed { + dv.DeviceStatus = pkg.Set(dv.DeviceStatus, pkg.DeviceStatusFailedSmart) + } + + return nil +} diff --git a/webapp/backend/pkg/models/device_summary.go b/webapp/backend/pkg/models/device_summary.go new file mode 100644 index 0000000..c1781e3 --- /dev/null +++ b/webapp/backend/pkg/models/device_summary.go @@ -0,0 +1,19 @@ +package models + +import ( + "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" + "time" +) + +type DeviceSummary struct { + Device Device `json:"device"` + + SmartResults *SmartSummary `json:"smart,omitempty"` + TempHistory []measurements.SmartTemperature `json:"temp_history,omitempty"` +} +type SmartSummary struct { + // Collector Summary Data + CollectorDate time.Time `json:"collector_date,omitempty"` + Temp int64 `json:"temp,omitempty"` + PowerOnHours int64 `json:"power_on_hours,omitempty"` +} diff --git a/webapp/backend/pkg/models/measurements/smart.go b/webapp/backend/pkg/models/measurements/smart.go new file mode 100644 index 0000000..20524ff --- /dev/null +++ b/webapp/backend/pkg/models/measurements/smart.go @@ -0,0 +1,198 @@ +package measurements + +import ( + "fmt" + "github.com/analogj/scrutiny/webapp/backend/pkg" + "github.com/analogj/scrutiny/webapp/backend/pkg/metadata" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" + "log" + "strings" + "time" +) + +type Smart struct { + Date time.Time `json:"date"` + DeviceWWN string `json:"device_wwn"` //(tag) + DeviceProtocol string `json:"device_protocol"` + + //Metrics (fields) + Temp int64 `json:"temp"` + PowerOnHours int64 `json:"power_on_hours"` + PowerCycleCount int64 `json:"power_cycle_count"` + + //Attributes (fields) + Attributes map[string]SmartAttribute `json:"attrs"` +} + +func (sm *Smart) Flatten() (tags map[string]string, fields map[string]interface{}) { + tags = map[string]string{ + "device_wwn": sm.DeviceWWN, + "device_protocol": sm.DeviceProtocol, + } + + fields = map[string]interface{}{ + "temp": sm.Temp, + "power_on_hours": sm.PowerOnHours, + "power_cycle_count": sm.PowerCycleCount, + } + + for _, attr := range sm.Attributes { + for attrKey, attrVal := range attr.Flatten() { + fields[attrKey] = attrVal + } + } + + return tags, fields +} + +func NewSmartFromInfluxDB(attrs map[string]interface{}) (*Smart, error) { + //go though the massive map returned from influxdb. If a key is associated with the Smart struct, assign it. If it starts with "attr.*" group it by attributeId, and pass to attribute inflate. + + sm := Smart{ + //required fields + Date: attrs["_time"].(time.Time), + DeviceWWN: attrs["device_wwn"].(string), + DeviceProtocol: attrs["device_protocol"].(string), + + Attributes: map[string]SmartAttribute{}, + } + + log.Printf("Prefetched Smart: %v\n", sm) + + //two steps (because we dont know the + for key, val := range attrs { + log.Printf("Found Attribute (%s = %v)\n", key, val) + + switch key { + case "temp": + sm.Temp = val.(int64) + case "power_on_hours": + sm.PowerOnHours = val.(int64) + case "power_cycle_count": + sm.PowerCycleCount = val.(int64) + default: + // this key is unknown. + if !strings.HasPrefix(key, "attr.") { + continue + } + //this is a attribute, lets group it with its related "siblings", populating a SmartAttribute object + keyParts := strings.Split(key, ".") + attributeId := keyParts[1] + if _, ok := sm.Attributes[attributeId]; !ok { + // init the attribute group + if sm.DeviceProtocol == pkg.DeviceProtocolAta { + sm.Attributes[attributeId] = &SmartAtaAttribute{} + } else if sm.DeviceProtocol == pkg.DeviceProtocolNvme { + sm.Attributes[attributeId] = &SmartNvmeAttribute{} + } else if sm.DeviceProtocol == pkg.DeviceProtocolScsi { + sm.Attributes[attributeId] = &SmartScsiAttribute{} + } else { + return nil, fmt.Errorf("Unknown Device Protocol: %s", sm.DeviceProtocol) + } + } + + sm.Attributes[attributeId].Inflate(key, val) + } + + } + + log.Printf("########NUMBER OF ATTRIBUTES: %v", len(sm.Attributes)) + log.Printf("########SMART: %v", sm) + + //panic("ERROR HERE.") + + //log.Printf("Sm.Attributes: %v", sm.Attributes) + //log.Printf("sm.Attributes[attributeId]: %v", sm.Attributes[attributeId]) + + return &sm, nil +} + +//Parse Collector SMART data results and create Smart object (and associated SmartAtaAttribute entries) +func (sm *Smart) FromCollectorSmartInfo(wwn string, info collector.SmartInfo) error { + sm.DeviceWWN = wwn + sm.Date = time.Unix(info.LocalTime.TimeT, 0) + + //smart metrics + sm.Temp = info.Temperature.Current + sm.PowerCycleCount = info.PowerCycleCount + sm.PowerOnHours = info.PowerOnTime.Hours + + sm.DeviceProtocol = info.Device.Protocol + // process ATA/NVME/SCSI protocol data + sm.Attributes = map[string]SmartAttribute{} + if sm.DeviceProtocol == pkg.DeviceProtocolAta { + sm.ProcessAtaSmartInfo(info) + } else if sm.DeviceProtocol == pkg.DeviceProtocolNvme { + sm.ProcessNvmeSmartInfo(info) + } else if sm.DeviceProtocol == pkg.DeviceProtocolScsi { + sm.ProcessScsiSmartInfo(info) + } + + return nil +} + +//generate SmartAtaAttribute entries from Scrutiny Collector Smart data. +func (sm *Smart) ProcessAtaSmartInfo(info collector.SmartInfo) { + for _, collectorAttr := range info.AtaSmartAttributes.Table { + attrModel := SmartAtaAttribute{ + AttributeId: collectorAttr.ID, + Name: collectorAttr.Name, + Value: collectorAttr.Value, + Worst: collectorAttr.Worst, + Threshold: collectorAttr.Thresh, + RawValue: collectorAttr.Raw.Value, + RawString: collectorAttr.Raw.String, + WhenFailed: collectorAttr.WhenFailed, + } + + //now that we've parsed the data from the smartctl response, lets match it against our metadata rules and add additional Scrutiny specific data. + if smartMetadata, ok := metadata.AtaMetadata[collectorAttr.ID]; ok { + attrModel.Name = smartMetadata.DisplayName + if smartMetadata.Transform != nil { + attrModel.TransformedValue = smartMetadata.Transform(attrModel.Value, attrModel.RawValue, attrModel.RawString) + } + } + sm.Attributes[string(collectorAttr.ID)] = &attrModel + } +} + +//generate SmartNvmeAttribute entries from Scrutiny Collector Smart data. +func (sm *Smart) ProcessNvmeSmartInfo(info collector.SmartInfo) { + sm.Attributes = map[string]SmartAttribute{ + "critical_warning": &SmartNvmeAttribute{AttributeId: "critical_warning", Name: "Critical Warning", Value: info.NvmeSmartHealthInformationLog.CriticalWarning, Threshold: 0}, + "temperature": &SmartNvmeAttribute{AttributeId: "temperature", Name: "Temperature", Value: info.NvmeSmartHealthInformationLog.Temperature, Threshold: -1}, + "available_spare": &SmartNvmeAttribute{AttributeId: "available_spare", Name: "Available Spare", Value: info.NvmeSmartHealthInformationLog.AvailableSpare, Threshold: info.NvmeSmartHealthInformationLog.AvailableSpareThreshold}, + "percentage_used": &SmartNvmeAttribute{AttributeId: "percentage_used", Name: "Percentage Used", Value: info.NvmeSmartHealthInformationLog.PercentageUsed, Threshold: 100}, + "data_units_read": &SmartNvmeAttribute{AttributeId: "data_units_read", Name: "Data Units Read", Value: info.NvmeSmartHealthInformationLog.DataUnitsRead, Threshold: -1}, + "data_units_written": &SmartNvmeAttribute{AttributeId: "data_units_written", Name: "Data Units Written", Value: info.NvmeSmartHealthInformationLog.DataUnitsWritten, Threshold: -1}, + "host_reads": &SmartNvmeAttribute{AttributeId: "host_reads", Name: "Host Reads", Value: info.NvmeSmartHealthInformationLog.HostReads, Threshold: -1}, + "host_writes": &SmartNvmeAttribute{AttributeId: "host_writes", Name: "Host Writes", Value: info.NvmeSmartHealthInformationLog.HostWrites, Threshold: -1}, + "controller_busy_time": &SmartNvmeAttribute{AttributeId: "controller_busy_time", Name: "Controller Busy Time", Value: info.NvmeSmartHealthInformationLog.ControllerBusyTime, Threshold: -1}, + "power_cycles": &SmartNvmeAttribute{AttributeId: "power_cycles", Name: "Power Cycles", Value: info.NvmeSmartHealthInformationLog.PowerCycles, Threshold: -1}, + "power_on_hours": &SmartNvmeAttribute{AttributeId: "power_on_hours", Name: "Power on Hours", Value: info.NvmeSmartHealthInformationLog.PowerOnHours, Threshold: -1}, + "unsafe_shutdowns": &SmartNvmeAttribute{AttributeId: "unsafe_shutdowns", Name: "Unsafe Shutdowns", Value: info.NvmeSmartHealthInformationLog.UnsafeShutdowns, Threshold: -1}, + "media_errors": &SmartNvmeAttribute{AttributeId: "media_errors", Name: "Media Errors", Value: info.NvmeSmartHealthInformationLog.MediaErrors, Threshold: 0}, + "num_err_log_entries": &SmartNvmeAttribute{AttributeId: "num_err_log_entries", Name: "Numb Err Log Entries", Value: info.NvmeSmartHealthInformationLog.NumErrLogEntries, Threshold: 0}, + "warning_temp_time": &SmartNvmeAttribute{AttributeId: "warning_temp_time", Name: "Warning Temp Time", Value: info.NvmeSmartHealthInformationLog.WarningTempTime, Threshold: -1}, + "critical_comp_time": &SmartNvmeAttribute{AttributeId: "critical_comp_time", Name: "Critical CompTime", Value: info.NvmeSmartHealthInformationLog.CriticalCompTime, Threshold: -1}, + } +} + +//generate SmartScsiAttribute entries from Scrutiny Collector Smart data. +func (sm *Smart) ProcessScsiSmartInfo(info collector.SmartInfo) { + sm.Attributes = map[string]SmartAttribute{ + "scsi_grown_defect_list": &SmartScsiAttribute{AttributeId: "scsi_grown_defect_list", Name: "Grown Defect List", Value: info.ScsiGrownDefectList, Threshold: 0}, + "read_errors_corrected_by_eccfast": &SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccfast", Name: "Read Errors Corrected by ECC Fast", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccfast, Threshold: -1}, + "read_errors_corrected_by_eccdelayed": &SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccdelayed", Name: "Read Errors Corrected by ECC Delayed", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccdelayed, Threshold: -1}, + "read_errors_corrected_by_rereads_rewrites": &SmartScsiAttribute{AttributeId: "read_errors_corrected_by_rereads_rewrites", Name: "Read Errors Corrected by ReReads/ReWrites", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByRereadsRewrites, Threshold: 0}, + "read_total_errors_corrected": &SmartScsiAttribute{AttributeId: "read_total_errors_corrected", Name: "Read Total Errors Corrected", Value: info.ScsiErrorCounterLog.Read.TotalErrorsCorrected, Threshold: -1}, + "read_correction_algorithm_invocations": &SmartScsiAttribute{AttributeId: "read_correction_algorithm_invocations", Name: "Read Correction Algorithm Invocations", Value: info.ScsiErrorCounterLog.Read.CorrectionAlgorithmInvocations, Threshold: -1}, + "read_total_uncorrected_errors": &SmartScsiAttribute{AttributeId: "read_total_uncorrected_errors", Name: "Read Total Uncorrected Errors", Value: info.ScsiErrorCounterLog.Read.TotalUncorrectedErrors, Threshold: 0}, + "write_errors_corrected_by_eccfast": &SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccfast", Name: "Write Errors Corrected by ECC Fast", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccfast, Threshold: -1}, + "write_errors_corrected_by_eccdelayed": &SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccdelayed", Name: "Write Errors Corrected by ECC Delayed", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccdelayed, Threshold: -1}, + "write_errors_corrected_by_rereads_rewrites": &SmartScsiAttribute{AttributeId: "write_errors_corrected_by_rereads_rewrites", Name: "Write Errors Corrected by ReReads/ReWrites", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByRereadsRewrites, Threshold: 0}, + "write_total_errors_corrected": &SmartScsiAttribute{AttributeId: "write_total_errors_corrected", Name: "Write Total Errors Corrected", Value: info.ScsiErrorCounterLog.Write.TotalErrorsCorrected, Threshold: -1}, + "write_correction_algorithm_invocations": &SmartScsiAttribute{AttributeId: "write_correction_algorithm_invocations", Name: "Write Correction Algorithm Invocations", Value: info.ScsiErrorCounterLog.Write.CorrectionAlgorithmInvocations, Threshold: -1}, + "write_total_uncorrected_errors": &SmartScsiAttribute{AttributeId: "write_total_uncorrected_errors", Name: "Write Total Uncorrected Errors", Value: info.ScsiErrorCounterLog.Write.TotalUncorrectedErrors, Threshold: 0}, + } +} diff --git a/webapp/backend/pkg/models/measurements/smart_ata_attribute.go b/webapp/backend/pkg/models/measurements/smart_ata_attribute.go new file mode 100644 index 0000000..691cac7 --- /dev/null +++ b/webapp/backend/pkg/models/measurements/smart_ata_attribute.go @@ -0,0 +1,151 @@ +package measurements + +import ( + "fmt" + "strconv" + "strings" +) + +const SmartAttributeStatusPassed = "passed" +const SmartAttributeStatusFailed = "failed" +const SmartAttributeStatusWarning = "warn" + +type SmartAtaAttribute struct { + AttributeId int `json:"attribute_id"` + Name string `json:"name"` + Value int64 `json:"value"` + Threshold int64 `json:"thresh"` + Worst int64 `json:"worst"` + RawValue int64 `json:"raw_value"` + RawString string `json:"raw_string"` + WhenFailed string `json:"when_failed"` + + //Generated data + TransformedValue int64 `json:"transformed_value"` + Status string `json:"status,omitempty"` + StatusReason string `json:"status_reason,omitempty"` + FailureRate float64 `json:"failure_rate,omitempty"` +} + +func (sa *SmartAtaAttribute) Flatten() map[string]interface{} { + + idString := strconv.Itoa(sa.AttributeId) + + return map[string]interface{}{ + fmt.Sprintf("attr.%s.attribute_id", idString): idString, + fmt.Sprintf("attr.%s.name", idString): sa.Name, + fmt.Sprintf("attr.%s.value", idString): sa.Value, + fmt.Sprintf("attr.%s.worst", idString): sa.Worst, + fmt.Sprintf("attr.%s.thresh", idString): sa.Threshold, + fmt.Sprintf("attr.%s.raw_value", idString): sa.RawValue, + fmt.Sprintf("attr.%s.raw_string", idString): sa.RawString, + fmt.Sprintf("attr.%s.when_failed", idString): sa.WhenFailed, + } +} +func (sa *SmartAtaAttribute) Inflate(key string, val interface{}) { + if val == nil { + return + } + keyParts := strings.Split(key, ".") + + switch keyParts[2] { + case "attribute_id": + attrId, err := strconv.Atoi(val.(string)) + if err == nil { + sa.AttributeId = attrId + } + case "name": + sa.Name = val.(string) + case "value": + sa.Value = val.(int64) + case "worst": + sa.Worst = val.(int64) + case "thresh": + sa.Threshold = val.(int64) + case "raw_value": + sa.RawValue = val.(int64) + case "raw_string": + sa.RawString = val.(string) + case "when_failed": + sa.WhenFailed = val.(string) + } +} + +// +////populate attribute status, using SMART Thresholds & Observed Metadata +//func (sa *SmartAtaAttribute) PopulateAttributeStatus() { +// if strings.ToUpper(sa.WhenFailed) == SmartWhenFailedFailingNow { +// //this attribute has previously failed +// sa.Status = SmartAttributeStatusFailed +// sa.StatusReason = "Attribute is failing manufacturer SMART threshold" +// +// } else if strings.ToUpper(sa.WhenFailed) == SmartWhenFailedInThePast { +// sa.Status = SmartAttributeStatusWarning +// sa.StatusReason = "Attribute has previously failed manufacturer SMART threshold" +// } +// +// if smartMetadata, ok := metadata.AtaMetadata[sa.AttributeId]; ok { +// sa.MetadataObservedThresholdStatus(smartMetadata) +// } +// +// //check if status is blank, set to "passed" +// if len(sa.Status) == 0 { +// sa.Status = SmartAttributeStatusPassed +// } +//} +// +//// compare the attribute (raw, normalized, transformed) value to observed thresholds, and update status if necessary +//func (sa *SmartAtaAttribute) MetadataObservedThresholdStatus(smartMetadata metadata.AtaAttributeMetadata) { +// //TODO: multiple rules +// // try to predict the failure rates for observed thresholds that have 0 failure rate and error bars. +// // - if the attribute is critical +// // - the failure rate is over 10 - set to failed +// // - the attribute does not match any threshold, set to warn +// // - if the attribute is not critical +// // - if failure rate is above 20 - set to failed +// // - if failure rate is above 10 but below 20 - set to warn +// +// //update the smart attribute status based on Observed thresholds. +// var value int64 +// if smartMetadata.DisplayType == metadata.AtaSmartAttributeDisplayTypeNormalized { +// value = int64(sa.Value) +// } else if smartMetadata.DisplayType == metadata.AtaSmartAttributeDisplayTypeTransformed { +// value = sa.TransformedValue +// } else { +// value = sa.RawValue +// } +// +// for _, obsThresh := range smartMetadata.ObservedThresholds { +// +// //check if "value" is in this bucket +// if ((obsThresh.Low == obsThresh.High) && value == obsThresh.Low) || +// (obsThresh.Low < value && value <= obsThresh.High) { +// sa.FailureRate = obsThresh.AnnualFailureRate +// +// if smartMetadata.Critical { +// if obsThresh.AnnualFailureRate >= 0.10 { +// sa.Status = SmartAttributeStatusFailed +// sa.StatusReason = "Observed Failure Rate for Critical Attribute is greater than 10%" +// } +// } else { +// if obsThresh.AnnualFailureRate >= 0.20 { +// sa.Status = SmartAttributeStatusFailed +// sa.StatusReason = "Observed Failure Rate for Attribute is greater than 20%" +// } else if obsThresh.AnnualFailureRate >= 0.10 { +// sa.Status = SmartAttributeStatusWarning +// sa.StatusReason = "Observed Failure Rate for Attribute is greater than 10%" +// } +// } +// +// //we've found the correct bucket, we can drop out of this loop +// return +// } +// } +// // no bucket found +// if smartMetadata.Critical { +// sa.Status = SmartAttributeStatusWarning +// sa.StatusReason = "Could not determine Observed Failure Rate for Critical Attribute" +// } +// +// return +//} diff --git a/webapp/backend/pkg/models/measurements/smart_attribute.go b/webapp/backend/pkg/models/measurements/smart_attribute.go new file mode 100644 index 0000000..1d93bc8 --- /dev/null +++ b/webapp/backend/pkg/models/measurements/smart_attribute.go @@ -0,0 +1,6 @@ +package measurements + +type SmartAttribute interface { + Flatten() (fields map[string]interface{}) + Inflate(key string, val interface{}) +} diff --git a/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go b/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go new file mode 100644 index 0000000..2705ea9 --- /dev/null +++ b/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go @@ -0,0 +1,68 @@ +package measurements + +import ( + "fmt" + "strings" +) + +type SmartNvmeAttribute struct { + AttributeId string `json:"attribute_id"` //json string from smartctl + Name string `json:"name"` + Value int64 `json:"value"` + Threshold int64 `json:"thresh"` + + TransformedValue int64 `json:"transformed_value"` + Status string `json:"status,omitempty"` + StatusReason string `json:"status_reason,omitempty"` + FailureRate float64 `json:"failure_rate,omitempty"` +} + +func (sa *SmartNvmeAttribute) Flatten() map[string]interface{} { + return map[string]interface{}{ + fmt.Sprintf("attr.%s.attribute_id", sa.AttributeId): sa.AttributeId, + fmt.Sprintf("attr.%s.name", sa.AttributeId): sa.Name, + fmt.Sprintf("attr.%s.value", sa.AttributeId): sa.Value, + fmt.Sprintf("attr.%s.thresh", sa.AttributeId): sa.Threshold, + } +} +func (sa *SmartNvmeAttribute) Inflate(key string, val interface{}) { + if val == nil { + return + } + + keyParts := strings.Split(key, ".") + + switch keyParts[2] { + case "attribute_id": + sa.AttributeId = val.(string) + case "name": + sa.Name = val.(string) + case "value": + sa.Value = val.(int64) + case "thresh": + sa.Threshold = val.(int64) + } +} + +// +////populate attribute status, using SMART Thresholds & Observed Metadata +//func (sa *SmartNvmeAttribute) PopulateAttributeStatus() { +// +// //-1 is a special number meaning no threshold. +// if sa.Threshold != -1 { +// if smartMetadata, ok := metadata.NmveMetadata[sa.AttributeId]; ok { +// //check what the ideal is. Ideal tells us if we our recorded value needs to be above, or below the threshold +// if (smartMetadata.Ideal == "low" && sa.Value > sa.Threshold) || +// (smartMetadata.Ideal == "high" && sa.Value < sa.Threshold) { +// sa.Status = SmartAttributeStatusFailed +// sa.StatusReason = "Attribute is failing recommended SMART threshold" +// } +// } +// } +// //TODO: eventually figure out the critical_warning bits and determine correct error messages here. +// +// //check if status is blank, set to "passed" +// if len(sa.Status) == 0 { +// sa.Status = SmartAttributeStatusPassed +// } +//} diff --git a/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go b/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go new file mode 100644 index 0000000..830036c --- /dev/null +++ b/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go @@ -0,0 +1,67 @@ +package measurements + +import ( + "fmt" + "strings" +) + +type SmartScsiAttribute struct { + AttributeId string `json:"attribute_id"` //json string from smartctl + Name string `json:"name"` + Value int64 `json:"value"` + Threshold int64 `json:"thresh"` + + TransformedValue int64 `json:"transformed_value"` + Status string `json:"status,omitempty"` + StatusReason string `json:"status_reason,omitempty"` + FailureRate float64 `json:"failure_rate,omitempty"` +} + +func (sa *SmartScsiAttribute) Flatten() map[string]interface{} { + return map[string]interface{}{ + fmt.Sprintf("attr.%s.attribute_id", sa.AttributeId): sa.AttributeId, + fmt.Sprintf("attr.%s.name", sa.AttributeId): sa.Name, + fmt.Sprintf("attr.%s.value", sa.AttributeId): sa.Value, + fmt.Sprintf("attr.%s.thresh", sa.AttributeId): sa.Threshold, + } +} +func (sa *SmartScsiAttribute) Inflate(key string, val interface{}) { + if val == nil { + return + } + + keyParts := strings.Split(key, ".") + + switch keyParts[2] { + case "attribute_id": + sa.AttributeId = val.(string) + case "name": + sa.Name = val.(string) + case "value": + sa.Value = val.(int64) + case "thresh": + sa.Threshold = val.(int64) + } +} + +// +////populate attribute status, using SMART Thresholds & Observed Metadata +//func (sa *SmartScsiAttribute) PopulateAttributeStatus() { +// +// //-1 is a special number meaning no threshold. +// if sa.Threshold != -1 { +// if smartMetadata, ok := metadata.NmveMetadata[sa.AttributeId]; ok { +// //check what the ideal is. Ideal tells us if we our recorded value needs to be above, or below the threshold +// if (smartMetadata.Ideal == "low" && sa.Value > sa.Threshold) || +// (smartMetadata.Ideal == "high" && sa.Value < sa.Threshold) { +// sa.Status = SmartAttributeStatusFailed +// sa.StatusReason = "Attribute is failing recommended SMART threshold" +// } +// } +// } +// +// //check if status is blank, set to "passed" +// if len(sa.Status) == 0 { +// sa.Status = SmartAttributeStatusPassed +// } +//} diff --git a/webapp/backend/pkg/models/measurements/smart_temperature.go b/webapp/backend/pkg/models/measurements/smart_temperature.go new file mode 100644 index 0000000..06f4d74 --- /dev/null +++ b/webapp/backend/pkg/models/measurements/smart_temperature.go @@ -0,0 +1,29 @@ +package measurements + +import ( + "time" +) + +type SmartTemperature struct { + Date time.Time `json:"date"` + Temp int64 `json:"temp"` +} + +func (st *SmartTemperature) Flatten() (tags map[string]string, fields map[string]interface{}) { + fields = map[string]interface{}{ + "temp": st.Temp, + } + tags = map[string]string{} + + return tags, fields +} + +func (st *SmartTemperature) Inflate(key string, val interface{}) { + if val == nil { + return + } + + if key == "temp" { + st.Temp = val.(int64) + } +} diff --git a/webapp/backend/pkg/models/measurements/smart_test.go b/webapp/backend/pkg/models/measurements/smart_test.go new file mode 100644 index 0000000..a1fde28 --- /dev/null +++ b/webapp/backend/pkg/models/measurements/smart_test.go @@ -0,0 +1,141 @@ +package measurements_test + +//func TestFromCollectorSmartInfo(t *testing.T) { +// //setup +// smartDataFile, err := os.Open("../testdata/smart-ata.json") +// require.NoError(t, err) +// defer smartDataFile.Close() +// +// var smartJson collector.SmartInfo +// +// smartDataBytes, err := ioutil.ReadAll(smartDataFile) +// require.NoError(t, err) +// err = json.Unmarshal(smartDataBytes, &smartJson) +// require.NoError(t, err) +// +// //test +// smartMdl := db.Smart{} +// err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) +// +// //assert +// require.NoError(t, err) +// require.Equal(t, "WWN-test", smartMdl.DeviceWWN) +// require.Equal(t, "passed", smartMdl.SmartStatus) +// require.Equal(t, 18, len(smartMdl.Attributes)) +// +// //check that temperature was correctly parsed +// for _, attr := range smartMdl.Attributes { +// if attr.AttributeId == 194 { +// require.Equal(t, int64(163210330144), attr.RawValue) +// require.Equal(t, int64(32), attr.TransformedValue) +// } +// } +//} +// +//func TestFromCollectorSmartInfo_Fail(t *testing.T) { +// //setup +// smartDataFile, err := os.Open("../testdata/smart-fail.json") +// require.NoError(t, err) +// defer smartDataFile.Close() +// +// var smartJson collector.SmartInfo +// +// smartDataBytes, err := ioutil.ReadAll(smartDataFile) +// require.NoError(t, err) +// err = json.Unmarshal(smartDataBytes, &smartJson) +// require.NoError(t, err) +// +// //test +// smartMdl := db.Smart{} +// err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) +// +// //assert +// require.NoError(t, err) +// require.Equal(t, "WWN-test", smartMdl.DeviceWWN) +// require.Equal(t, "failed", smartMdl.SmartStatus) +// require.Equal(t, 0, len(smartMdl.AtaAttributes)) +// require.Equal(t, 0, len(smartMdl.NvmeAttributes)) +// require.Equal(t, 0, len(smartMdl.ScsiAttributes)) +//} +// +//func TestFromCollectorSmartInfo_Fail2(t *testing.T) { +// //setup +// smartDataFile, err := os.Open("../testdata/smart-fail2.json") +// require.NoError(t, err) +// defer smartDataFile.Close() +// +// var smartJson collector.SmartInfo +// +// smartDataBytes, err := ioutil.ReadAll(smartDataFile) +// require.NoError(t, err) +// err = json.Unmarshal(smartDataBytes, &smartJson) +// require.NoError(t, err) +// +// //test +// smartMdl := db.Smart{} +// err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) +// +// //assert +// require.NoError(t, err) +// require.Equal(t, "WWN-test", smartMdl.DeviceWWN) +// require.Equal(t, "failed", smartMdl.SmartStatus) +// require.Equal(t, 17, len(smartMdl.Attributes)) +//} +// +//func TestFromCollectorSmartInfo_Nvme(t *testing.T) { +// //setup +// smartDataFile, err := os.Open("../testdata/smart-nvme.json") +// require.NoError(t, err) +// defer smartDataFile.Close() +// +// var smartJson collector.SmartInfo +// +// smartDataBytes, err := ioutil.ReadAll(smartDataFile) +// require.NoError(t, err) +// err = json.Unmarshal(smartDataBytes, &smartJson) +// require.NoError(t, err) +// +// //test +// smartMdl := db.Smart{} +// err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) +// +// //assert +// require.NoError(t, err) +// require.Equal(t, "WWN-test", smartMdl.DeviceWWN) +// require.Equal(t, "passed", smartMdl.SmartStatus) +// require.Equal(t, 0, len(smartMdl.AtaAttributes)) +// require.Equal(t, 16, len(smartMdl.NvmeAttributes)) +// require.Equal(t, 0, len(smartMdl.ScsiAttributes)) +// +// require.Equal(t, 111303174, smartMdl.NvmeAttributes[6].Value) +// require.Equal(t, 83170961, smartMdl.NvmeAttributes[7].Value) +//} +// +//func TestFromCollectorSmartInfo_Scsi(t *testing.T) { +// //setup +// smartDataFile, err := os.Open("../testdata/smart-scsi.json") +// require.NoError(t, err) +// defer smartDataFile.Close() +// +// var smartJson collector.SmartInfo +// +// smartDataBytes, err := ioutil.ReadAll(smartDataFile) +// require.NoError(t, err) +// err = json.Unmarshal(smartDataBytes, &smartJson) +// require.NoError(t, err) +// +// //test +// smartMdl := db.Smart{} +// err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) +// +// //assert +// require.NoError(t, err) +// require.Equal(t, "WWN-test", smartMdl.DeviceWWN) +// require.Equal(t, "passed", smartMdl.SmartStatus) +// require.Equal(t, 0, len(smartMdl.AtaAttributes)) +// require.Equal(t, 0, len(smartMdl.NvmeAttributes)) +// require.Equal(t, 13, len(smartMdl.ScsiAttributes)) +// +// require.Equal(t, 56, smartMdl.ScsiAttributes[0].Value) +// require.Equal(t, 300357663, smartMdl.ScsiAttributes[4].Value) //total_errors_corrected +//} diff --git a/webapp/backend/pkg/models/setting.go b/webapp/backend/pkg/models/setting.go new file mode 100644 index 0000000..d9a1d6b --- /dev/null +++ b/webapp/backend/pkg/models/setting.go @@ -0,0 +1,5 @@ +package models + +// Temperature Format +// Date Format +// Device History window diff --git a/webapp/backend/pkg/models/testdata/smart-ata-date.json b/webapp/backend/pkg/models/testdata/smart-ata-date.json new file mode 100644 index 0000000..f654a3a --- /dev/null +++ b/webapp/backend/pkg/models/testdata/smart-ata-date.json @@ -0,0 +1,846 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 0 + ], + "svn_revision": "4883", + "platform_info": "x86_64-linux-4.19.128-flatcar", + "build_info": "(local build)", + "argv": [ + "smartctl", + "-j", + "-a", + "/dev/sdb" + ], + "exit_status": 0 + }, + "device": { + "name": "/dev/sdb", + "info_name": "/dev/sdb [SAT]", + "type": "sat", + "protocol": "ATA" + }, + "model_name": "WDC WD140EDFZ-11A0VA0", + "serial_number": "9RK1XXXX", + "wwn": { + "naa": 5, + "oui": 3274, + "id": 10283057623 + }, + "firmware_version": "81.00A81", + "user_capacity": { + "blocks": 27344764928, + "bytes": 14000519643136 + }, + "logical_block_size": 512, + "physical_block_size": 4096, + "rotation_rate": 5400, + "form_factor": { + "ata_value": 2, + "name": "3.5 inches" + }, + "in_smartctl_database": false, + "ata_version": { + "string": "ACS-2, ATA8-ACS T13/1699-D revision 4", + "major_value": 1020, + "minor_value": 41 + }, + "sata_version": { + "string": "SATA 3.2", + "value": 255 + }, + "interface_speed": { + "max": { + "sata_value": 14, + "string": "6.0 Gb/s", + "units_per_second": 60, + "bits_per_unit": 100000000 + }, + "current": { + "sata_value": 3, + "string": "6.0 Gb/s", + "units_per_second": 60, + "bits_per_unit": 100000000 + } + }, + "local_time": { + "time_t": 1611419146, + "asctime": "Sun Jun 30 00:03:30 2021 UTC" + }, + "smart_status": { + "passed": true + }, + "ata_smart_data": { + "offline_data_collection": { + "status": { + "value": 130, + "string": "was completed without error", + "passed": true + }, + "completion_seconds": 101 + }, + "self_test": { + "status": { + "value": 241, + "string": "in progress, 10% remaining", + "remaining_percent": 10 + }, + "polling_minutes": { + "short": 2, + "extended": 1479 + } + }, + "capabilities": { + "values": [ + 91, + 3 + ], + "exec_offline_immediate_supported": true, + "offline_is_aborted_upon_new_cmd": false, + "offline_surface_scan_supported": true, + "self_tests_supported": true, + "conveyance_self_test_supported": false, + "selective_self_test_supported": true, + "attribute_autosave_enabled": true, + "error_logging_supported": true, + "gp_logging_supported": true + } + }, + "ata_sct_capabilities": { + "value": 61, + "error_recovery_control_supported": true, + "feature_control_supported": true, + "data_table_supported": true + }, + "ata_smart_attributes": { + "revision": 16, + "table": [ + { + "id": 1, + "name": "Raw_Read_Error_Rate", + "value": 100, + "worst": 100, + "thresh": 1, + "when_failed": "", + "flags": { + "value": 11, + "string": "PO-R-- ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": true, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 2, + "name": "Throughput_Performance", + "value": 135, + "worst": 135, + "thresh": 54, + "when_failed": "", + "flags": { + "value": 4, + "string": "--S--- ", + "prefailure": false, + "updated_online": false, + "performance": true, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 108, + "string": "108" + } + }, + { + "id": 3, + "name": "Spin_Up_Time", + "value": 81, + "worst": 81, + "thresh": 1, + "when_failed": "", + "flags": { + "value": 7, + "string": "POS--- ", + "prefailure": true, + "updated_online": true, + "performance": true, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 30089675132, + "string": "380 (Average 380)" + } + }, + { + "id": 4, + "name": "Start_Stop_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 18, + "string": "-O--C- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 9, + "string": "9" + } + }, + { + "id": 5, + "name": "Reallocated_Sector_Ct", + "value": 100, + "worst": 100, + "thresh": 1, + "when_failed": "", + "flags": { + "value": 51, + "string": "PO--CK ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 7, + "name": "Seek_Error_Rate", + "value": 100, + "worst": 100, + "thresh": 1, + "when_failed": "", + "flags": { + "value": 10, + "string": "-O-R-- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": true, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 8, + "name": "Seek_Time_Performance", + "value": 133, + "worst": 133, + "thresh": 20, + "when_failed": "", + "flags": { + "value": 4, + "string": "--S--- ", + "prefailure": false, + "updated_online": false, + "performance": true, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 18, + "string": "18" + } + }, + { + "id": 9, + "name": "Power_On_Hours", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 18, + "string": "-O--C- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 1730, + "string": "1730" + } + }, + { + "id": 10, + "name": "Spin_Retry_Count", + "value": 100, + "worst": 100, + "thresh": 1, + "when_failed": "", + "flags": { + "value": 18, + "string": "-O--C- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 12, + "name": "Power_Cycle_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 9, + "string": "9" + } + }, + { + "id": 22, + "name": "Unknown_Attribute", + "value": 100, + "worst": 100, + "thresh": 25, + "when_failed": "", + "flags": { + "value": 35, + "string": "PO---K ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": true + }, + "raw": { + "value": 100, + "string": "100" + } + }, + { + "id": 192, + "name": "Power-Off_Retract_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 329, + "string": "329" + } + }, + { + "id": 193, + "name": "Load_Cycle_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 18, + "string": "-O--C- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 329, + "string": "329" + } + }, + { + "id": 194, + "name": "Temperature_Celsius", + "value": 51, + "worst": 51, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 2, + "string": "-O---- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 163210330144, + "string": "32 (Min/Max 24/38)" + } + }, + { + "id": 196, + "name": "Reallocated_Event_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 197, + "name": "Current_Pending_Sector", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 34, + "string": "-O---K ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 198, + "name": "Offline_Uncorrectable", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 8, + "string": "---R-- ", + "prefailure": false, + "updated_online": false, + "performance": false, + "error_rate": true, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 199, + "name": "UDMA_CRC_Error_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 10, + "string": "-O-R-- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": true, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + } + ] + }, + "power_on_time": { + "hours": 1730 + }, + "power_cycle_count": 9, + "temperature": { + "current": 32 + }, + "ata_smart_error_log": { + "summary": { + "revision": 1, + "count": 0 + } + }, + "ata_smart_self_test_log": { + "standard": { + "revision": 1, + "table": [ + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1708 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1684 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1661 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1636 + }, + { + "type": { + "value": 2, + "string": "Extended offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1624 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1541 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1517 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1493 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1469 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1445 + }, + { + "type": { + "value": 2, + "string": "Extended offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1439 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1373 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1349 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1325 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1301 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1277 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1253 + }, + { + "type": { + "value": 2, + "string": "Extended offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1252 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1205 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1181 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1157 + } + ], + "count": 21, + "error_count_total": 0, + "error_count_outdated": 0 + } + }, + "ata_smart_selective_self_test_log": { + "revision": 1, + "table": [ + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 241, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 241, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 241, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 241, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 241, + "string": "Not_testing" + } + } + ], + "flags": { + "value": 0, + "remainder_scan_enabled": false + }, + "power_up_scan_resume_minutes": 0 + } +} diff --git a/webapp/backend/pkg/web/handler/get_device_details.go b/webapp/backend/pkg/web/handler/get_device_details.go index 4bee8fc..5807292 100644 --- a/webapp/backend/pkg/web/handler/get_device_details.go +++ b/webapp/backend/pkg/web/handler/get_device_details.go @@ -1,44 +1,25 @@ package handler import ( + "github.com/analogj/scrutiny/webapp/backend/pkg/database" "github.com/analogj/scrutiny/webapp/backend/pkg/metadata" - dbModels "github.com/analogj/scrutiny/webapp/backend/pkg/models/db" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" - "gorm.io/gorm" "net/http" ) func GetDeviceDetails(c *gin.Context) { - db := c.MustGet("DB").(*gorm.DB) logger := c.MustGet("LOGGER").(logrus.FieldLogger) - device := dbModels.Device{} - - if err := db.Preload("SmartResults", func(db *gorm.DB) *gorm.DB { - return db.Order("smarts.created_at DESC").Limit(40) - }). - Preload("SmartResults.AtaAttributes"). - Preload("SmartResults.NvmeAttributes"). - Preload("SmartResults.ScsiAttributes"). - Where("wwn = ?", c.Param("wwn")). - First(&device).Error; err != nil { + deviceRepo := c.MustGet("DEVICE_REPOSITORY").(database.DeviceRepo) + device, err := deviceRepo.GetDeviceDetails(c, c.Param("wwn")) + if err != nil { logger.Errorln("An error occurred while retrieving device details", err) c.JSON(http.StatusInternalServerError, gin.H{"success": false}) return } - if err := device.SquashHistory(); err != nil { - logger.Errorln("An error occurred while squashing device history", err) - c.JSON(http.StatusInternalServerError, gin.H{"success": false}) - return - } - - if err := device.ApplyMetadataRules(); err != nil { - logger.Errorln("An error occurred while applying scrutiny thresholds & rules", err) - c.JSON(http.StatusInternalServerError, gin.H{"success": false}) - return - } + smartResults, err := deviceRepo.GetSmartAttributeHistory(c, c.Param("wwn"), "", nil) var deviceMetadata interface{} if device.IsAta() { @@ -49,5 +30,5 @@ func GetDeviceDetails(c *gin.Context) { deviceMetadata = metadata.ScsiMetadata } - c.JSON(http.StatusOK, gin.H{"success": true, "data": device, "metadata": deviceMetadata}) + c.JSON(http.StatusOK, gin.H{"success": true, "data": map[string]interface{}{"device": device, "smart_results": smartResults}, "metadata": deviceMetadata}) } diff --git a/webapp/backend/pkg/web/handler/get_devices_summary.go b/webapp/backend/pkg/web/handler/get_devices_summary.go index b0c9c1c..8eb392f 100644 --- a/webapp/backend/pkg/web/handler/get_devices_summary.go +++ b/webapp/backend/pkg/web/handler/get_devices_summary.go @@ -1,31 +1,28 @@ package handler import ( - dbModels "github.com/analogj/scrutiny/webapp/backend/pkg/models/db" + "github.com/analogj/scrutiny/webapp/backend/pkg/database" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" - "gorm.io/gorm" "net/http" ) func GetDevicesSummary(c *gin.Context) { - db := c.MustGet("DB").(*gorm.DB) logger := c.MustGet("LOGGER").(logrus.FieldLogger) - devices := []dbModels.Device{} + deviceRepo := c.MustGet("DEVICE_REPOSITORY").(database.DeviceRepo) - //We need the last x (for now all) Smart objects for each Device, so that we can graph Temperature - //We also need the last - if err := db.Preload("SmartResults", func(db *gorm.DB) *gorm.DB { - return db.Order("smarts.created_at DESC") //OLD: .Limit(devicesCount) - }). - Find(&devices).Error; err != nil { - logger.Errorln("Could not get device summary from DB", err) + summary, err := deviceRepo.GetSummary(c) + if err != nil { + logger.Errorln("An error occurred while retrieving device summary", err) c.JSON(http.StatusInternalServerError, gin.H{"success": false}) return } c.JSON(http.StatusOK, gin.H{ "success": true, - "data": devices, + "data": map[string]interface{}{ + "summary": summary, + //"temperature": tem + }, }) } diff --git a/webapp/backend/pkg/web/handler/register_devices.go b/webapp/backend/pkg/web/handler/register_devices.go index 746278a..e1ddf95 100644 --- a/webapp/backend/pkg/web/handler/register_devices.go +++ b/webapp/backend/pkg/web/handler/register_devices.go @@ -1,22 +1,20 @@ package handler import ( - dbModels "github.com/analogj/scrutiny/webapp/backend/pkg/models/db" + "github.com/analogj/scrutiny/webapp/backend/pkg/database" + "github.com/analogj/scrutiny/webapp/backend/pkg/models" "github.com/gin-gonic/gin" - "gorm.io/gorm" - "gorm.io/gorm/clause" - "github.com/sirupsen/logrus" "net/http" ) // register devices that are detected by various collectors. -// This function is run everytime a collector is about to start a run. It can be used to update device data. +// This function is run everytime a collector is about to start a run. It can be used to update device metadata. func RegisterDevices(c *gin.Context) { - db := c.MustGet("DB").(*gorm.DB) + deviceRepo := c.MustGet("DEVICE_REPOSITORY").(database.DeviceRepo) logger := c.MustGet("LOGGER").(logrus.FieldLogger) - var collectorDeviceWrapper dbModels.DeviceWrapper + var collectorDeviceWrapper models.DeviceWrapper err := c.BindJSON(&collectorDeviceWrapper) if err != nil { logger.Errorln("Cannot parse detected devices", err) @@ -28,11 +26,7 @@ func RegisterDevices(c *gin.Context) { for _, dev := range collectorDeviceWrapper.Data { //insert devices into DB (and update specified columns if device is already registered) // update device fields that may change: (DeviceType, HostID) - if err := db.Clauses(clause.OnConflict{ - Columns: []clause.Column{{Name: "wwn"}}, - DoUpdates: clause.AssignmentColumns([]string{"host_id", "device_name", "device_type"}), - }).Create(&dev).Error; err != nil { - + if err := deviceRepo.RegisterDevice(c, dev); err != nil { errs = append(errs, err) } } @@ -44,7 +38,7 @@ func RegisterDevices(c *gin.Context) { }) return } else { - c.JSON(http.StatusOK, dbModels.DeviceWrapper{ + c.JSON(http.StatusOK, models.DeviceWrapper{ Success: true, Data: collectorDeviceWrapper.Data, }) diff --git a/webapp/backend/pkg/web/handler/send_test_notification.go b/webapp/backend/pkg/web/handler/send_test_notification.go index 52ba8f5..07a1d6c 100644 --- a/webapp/backend/pkg/web/handler/send_test_notification.go +++ b/webapp/backend/pkg/web/handler/send_test_notification.go @@ -1,8 +1,9 @@ package handler import ( + "github.com/analogj/scrutiny/webapp/backend/pkg" "github.com/analogj/scrutiny/webapp/backend/pkg/config" - dbModels "github.com/analogj/scrutiny/webapp/backend/pkg/models/db" + "github.com/analogj/scrutiny/webapp/backend/pkg/models" "github.com/analogj/scrutiny/webapp/backend/pkg/notify" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" @@ -20,7 +21,7 @@ func SendTestNotification(c *gin.Context) { Payload: notify.Payload{ FailureType: "EmailTest", DeviceSerial: "FAKEWDDJ324KSO", - DeviceType: dbModels.DeviceProtocolAta, + DeviceType: pkg.DeviceProtocolAta, DeviceName: "/dev/sda", Test: true, }, @@ -33,7 +34,7 @@ func SendTestNotification(c *gin.Context) { "errors": []string{err.Error()}, }) } else { - c.JSON(http.StatusOK, dbModels.DeviceWrapper{ + c.JSON(http.StatusOK, models.DeviceWrapper{ Success: true, }) } diff --git a/webapp/backend/pkg/web/handler/upload_device_metrics.go b/webapp/backend/pkg/web/handler/upload_device_metrics.go index 949116a..5abd134 100644 --- a/webapp/backend/pkg/web/handler/upload_device_metrics.go +++ b/webapp/backend/pkg/web/handler/upload_device_metrics.go @@ -1,20 +1,24 @@ package handler import ( + "github.com/analogj/scrutiny/webapp/backend/pkg" "github.com/analogj/scrutiny/webapp/backend/pkg/config" + "github.com/analogj/scrutiny/webapp/backend/pkg/database" "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" - dbModels "github.com/analogj/scrutiny/webapp/backend/pkg/models/db" "github.com/analogj/scrutiny/webapp/backend/pkg/notify" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" - "gorm.io/gorm" "net/http" ) func UploadDeviceMetrics(c *gin.Context) { - db := c.MustGet("DB").(*gorm.DB) + //db := c.MustGet("DB").(*gorm.DB) logger := c.MustGet("LOGGER").(logrus.FieldLogger) appConfig := c.MustGet("CONFIG").(config.Interface) + //influxWriteDb := c.MustGet("INFLUXDB_WRITE").(*api.WriteAPIBlocking) + deviceRepo := c.MustGet("DEVICE_REPOSITORY").(database.DeviceRepo) + + //appConfig := c.MustGet("CONFIG").(config.Interface) var collectorSmartData collector.SmartInfo err := c.BindJSON(&collectorSmartData) @@ -25,39 +29,39 @@ func UploadDeviceMetrics(c *gin.Context) { } //update the device information if necessary - var device dbModels.Device - db.Where("wwn = ?", c.Param("wwn")).First(&device) - device.UpdateFromCollectorSmartInfo(collectorSmartData) - if err := db.Model(&device).Updates(device).Error; err != nil { + updatedDevice, err := deviceRepo.UpdateDevice(c, c.Param("wwn"), collectorSmartData) + if err != nil { logger.Errorln("An error occurred while updating device data from smartctl metrics", err) c.JSON(http.StatusInternalServerError, gin.H{"success": false}) return } // insert smart info - deviceSmartData := dbModels.Smart{} - err = deviceSmartData.FromCollectorSmartInfo(c.Param("wwn"), collectorSmartData) + _, err = deviceRepo.SaveSmartAttributes(c, c.Param("wwn"), collectorSmartData) if err != nil { - logger.Errorln("Could not process SMART metrics", err) + logger.Errorln("An error occurred while saving smartctl metrics", err) c.JSON(http.StatusInternalServerError, gin.H{"success": false}) return } - if err := db.Create(&deviceSmartData).Error; err != nil { - logger.Errorln("An error occurred while saving smartctl metrics", err) + + // save smart temperature data (ignore failures) + err = deviceRepo.SaveSmartTemperature(c, c.Param("wwn"), updatedDevice.DeviceProtocol, collectorSmartData) + if err != nil { + logger.Errorln("An error occurred while saving smartctl temp data", err) c.JSON(http.StatusInternalServerError, gin.H{"success": false}) return } //check for error - if deviceSmartData.SmartStatus == dbModels.SmartStatusFailed { + if updatedDevice.DeviceStatus != pkg.DeviceStatusPassed { //send notifications testNotify := notify.Notify{ Config: appConfig, Payload: notify.Payload{ FailureType: notify.NotifyFailureTypeSmartFailure, - DeviceName: device.DeviceName, - DeviceType: device.DeviceProtocol, - DeviceSerial: device.SerialNumber, + DeviceName: updatedDevice.DeviceName, + DeviceType: updatedDevice.DeviceProtocol, + DeviceSerial: updatedDevice.SerialNumber, Test: false, }, Logger: logger, diff --git a/webapp/backend/pkg/web/middleware/repository.go b/webapp/backend/pkg/web/middleware/repository.go new file mode 100644 index 0000000..3fe58d2 --- /dev/null +++ b/webapp/backend/pkg/web/middleware/repository.go @@ -0,0 +1,22 @@ +package middleware + +import ( + "github.com/analogj/scrutiny/webapp/backend/pkg/config" + "github.com/analogj/scrutiny/webapp/backend/pkg/database" + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" +) + +func RepositoryMiddleware(appConfig config.Interface, globalLogger logrus.FieldLogger) gin.HandlerFunc { + + deviceRepo, err := database.NewScrutinyRepository(appConfig, globalLogger) + if err != nil { + panic(err) + } + + //TODO: determine where we can call defer deviceRepo.Close() + return func(c *gin.Context) { + c.Set("DEVICE_REPOSITORY", deviceRepo) + c.Next() + } +} diff --git a/webapp/backend/pkg/web/middleware/sqlite3.go b/webapp/backend/pkg/web/middleware/sqlite3.go deleted file mode 100644 index 3eeee13..0000000 --- a/webapp/backend/pkg/web/middleware/sqlite3.go +++ /dev/null @@ -1,59 +0,0 @@ -package middleware - -import ( - "fmt" - "github.com/analogj/scrutiny/webapp/backend/pkg/config" - "github.com/analogj/scrutiny/webapp/backend/pkg/models/db" - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" - "gorm.io/driver/sqlite" - "gorm.io/gorm" -) - -func DatabaseMiddleware(appConfig config.Interface, globalLogger logrus.FieldLogger) gin.HandlerFunc { - - //var database *gorm.DB - fmt.Printf("Trying to connect to database stored: %s\n", appConfig.GetString("web.database.location")) - database, err := gorm.Open(sqlite.Open(appConfig.GetString("web.database.location")), &gorm.Config{ - //TODO: figure out how to log database queries again. - //Logger: logger - }) - if err != nil { - panic("Failed to connect to database!") - } - - //database.SetLogger() - database.AutoMigrate(&db.Device{}) - database.AutoMigrate(&db.SelfTest{}) - database.AutoMigrate(&db.Smart{}) - database.AutoMigrate(&db.SmartAtaAttribute{}) - database.AutoMigrate(&db.SmartNvmeAttribute{}) - database.AutoMigrate(&db.SmartScsiAttribute{}) - - //TODO: detrmine where we can call defer database.Close() - return func(c *gin.Context) { - c.Set("DB", database) - c.Next() - } -} - -// GormLogger is a custom logger for Gorm, making it use logrus. -type GormLogger struct{ Logger logrus.FieldLogger } - -// Print handles log events from Gorm for the custom logger. -func (gl *GormLogger) Print(v ...interface{}) { - switch v[0] { - case "sql": - gl.Logger.WithFields( - logrus.Fields{ - "module": "gorm", - "type": "sql", - "rows": v[5], - "src_ref": v[1], - "values": v[4], - }, - ).Debug(v[3]) - case "log": - gl.Logger.WithFields(logrus.Fields{"module": "gorm", "type": "log"}).Print(v[2]) - } -} diff --git a/webapp/backend/pkg/web/server.go b/webapp/backend/pkg/web/server.go index af993e3..c685916 100644 --- a/webapp/backend/pkg/web/server.go +++ b/webapp/backend/pkg/web/server.go @@ -23,7 +23,7 @@ func (ae *AppEngine) Setup(logger logrus.FieldLogger) *gin.Engine { r := gin.New() r.Use(middleware.LoggerMiddleware(logger)) - r.Use(middleware.DatabaseMiddleware(ae.Config, logger)) + r.Use(middleware.RepositoryMiddleware(ae.Config, logger)) r.Use(middleware.ConfigMiddleware(ae.Config)) r.Use(gin.Recovery()) diff --git a/webapp/backend/pkg/web/server_test.go b/webapp/backend/pkg/web/server_test.go index 1b2d87f..01ec527 100644 --- a/webapp/backend/pkg/web/server_test.go +++ b/webapp/backend/pkg/web/server_test.go @@ -3,7 +3,7 @@ package web_test import ( "encoding/json" mock_config "github.com/analogj/scrutiny/webapp/backend/pkg/config/mock" - dbModels "github.com/analogj/scrutiny/webapp/backend/pkg/models/db" + "github.com/analogj/scrutiny/webapp/backend/pkg/models" "github.com/analogj/scrutiny/webapp/backend/pkg/web" "github.com/golang/mock/gomock" "github.com/sirupsen/logrus" @@ -319,7 +319,7 @@ func TestGetDevicesSummaryRoute_Nvme(t *testing.T) { req, _ = http.NewRequest("GET", "/api/summary", nil) router.ServeHTTP(sr, req) require.Equal(t, 200, sr.Code) - var device dbModels.DeviceWrapper + var device models.DeviceWrapper json.Unmarshal(sr.Body.Bytes(), &device) //assert diff --git a/webapp/frontend/src/app/data/mock/device/details/sda.ts b/webapp/frontend/src/app/data/mock/device/details/sda.ts index 2766943..733e2ee 100644 --- a/webapp/frontend/src/app/data/mock/device/details/sda.ts +++ b/webapp/frontend/src/app/data/mock/device/details/sda.ts @@ -1,1479 +1,151 @@ export const sda = { "data": { - "CreatedAt": "2020-08-28T07:55:27.751071002Z", - "UpdatedAt": "2020-09-08T21:39:26.571901-07:00", - "DeletedAt": null, - "wwn": "0x5002538e40a22954", - "device_name": "sda", - "manufacturer": "ATA", - "model_name": "Samsung_SSD_860_EVO_500GB", - "interface_type": "SCSI", - "interface_speed": "", - "host_id": "NAS", - "serial_number": "S3YZNB0KBXXXXXX", - "firmware": "002C", - "rotational_speed": 0, - "capacity": 1024209543168, - "form_factor": "", - "smart_support": false, - "device_protocol": "NVMe", - "device_type": "nvme", - "smart_results": [{ - "ID": 46, - "CreatedAt": "2020-09-08T21:39:26.572596-07:00", - "UpdatedAt": "2020-09-08T21:39:26.572596-07:00", + "device": { + "CreatedAt": "2021-06-24T21:17:31.301226-07:00", + "UpdatedAt": "2021-06-26T14:26:20.856273-07:00", "DeletedAt": null, + "wwn": "0x5002538e40a22954", + "device_name": "sda", + "manufacturer": "ATA", + "model_name": "Samsung_SSD_860_EVO_500GB", + "interface_type": "SCSI", + "interface_speed": "", + "serial_number": "S3YZNB0KBXXXXXX", + "firmware": "002C", + "rotational_speed": 0, + "capacity": 500107862016, + "form_factor": "", + "smart_support": false, + "device_protocol": "NVMe", + "device_type": "", + "label": "", + "host_id": "", + "device_status": 0 + }, + "smart_results": [{ + "date": "2020-06-10T12:01:02Z", "device_wwn": "0x5002538e40a22954", - "date": "2020-06-10T05:01:02-07:00", - "smart_status": "passed", + "device_protocol": "NVMe", "temp": 36, "power_on_hours": 2401, "power_cycle_count": 266, - "ata_attributes": [], - "nvme_attributes": [{ - "ID": 113, - "CreatedAt": "2020-09-08T21:39:26.572894-07:00", - "UpdatedAt": "2020-09-08T21:39:26.572894-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "critical_warning", - "name": "Critical Warning", - "value": 0, - "thresh": 0, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 97, - "CreatedAt": "2020-09-07T15:47:21.336744707Z", - "UpdatedAt": "2020-09-07T15:47:21.336744707Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "critical_warning", - "name": "Critical Warning", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 81, - "CreatedAt": "2020-09-07T15:38:56.633368699Z", - "UpdatedAt": "2020-09-07T15:38:56.633368699Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "critical_warning", - "name": "Critical Warning", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 65, - "CreatedAt": "2020-09-07T15:26:07.504953448Z", - "UpdatedAt": "2020-09-07T15:26:07.504953448Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "critical_warning", - "name": "Critical Warning", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 49, - "CreatedAt": "2020-09-07T15:19:17.467897283Z", - "UpdatedAt": "2020-09-07T15:19:17.467897283Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "critical_warning", - "name": "Critical Warning", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 33, - "CreatedAt": "2020-09-07T15:10:40.246090797Z", - "UpdatedAt": "2020-09-07T15:10:40.246090797Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "critical_warning", - "name": "Critical Warning", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 17, - "CreatedAt": "2020-09-06T23:14:39.849191275Z", - "UpdatedAt": "2020-09-06T23:14:39.849191275Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "critical_warning", - "name": "Critical Warning", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 1, - "CreatedAt": "2020-08-28T07:55:27.833308403Z", - "UpdatedAt": "2020-08-28T07:55:27.833308403Z", - "DeletedAt": null, - "smart_id": 4, - "attribute_id": "critical_warning", - "name": "Critical Warning", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 114, - "CreatedAt": "2020-09-08T21:39:26.573359-07:00", - "UpdatedAt": "2020-09-08T21:39:26.573359-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "temperature", - "name": "Temperature", - "value": 36, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 98, - "CreatedAt": "2020-09-07T15:47:21.336894307Z", - "UpdatedAt": "2020-09-07T15:47:21.336894307Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "temperature", - "name": "Temperature", - "value": 36, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 82, - "CreatedAt": "2020-09-07T15:38:56.6334864Z", - "UpdatedAt": "2020-09-07T15:38:56.6334864Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "temperature", - "name": "Temperature", - "value": 36, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 66, - "CreatedAt": "2020-09-07T15:26:07.505094452Z", - "UpdatedAt": "2020-09-07T15:26:07.505094452Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "temperature", - "name": "Temperature", - "value": 36, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 50, - "CreatedAt": "2020-09-07T15:19:17.468022483Z", - "UpdatedAt": "2020-09-07T15:19:17.468022483Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "temperature", - "name": "Temperature", - "value": 36, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 34, - "CreatedAt": "2020-09-07T15:10:40.246266999Z", - "UpdatedAt": "2020-09-07T15:10:40.246266999Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "temperature", - "name": "Temperature", - "value": 36, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 18, - "CreatedAt": "2020-09-06T23:14:39.849315479Z", - "UpdatedAt": "2020-09-06T23:14:39.849315479Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "temperature", - "name": "Temperature", - "value": 36, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 2, - "CreatedAt": "2020-08-28T07:55:27.833462173Z", - "UpdatedAt": "2020-08-28T07:55:27.833462173Z", - "DeletedAt": null, - "smart_id": 4, - "attribute_id": "temperature", - "name": "Temperature", - "value": 36, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 115, - "CreatedAt": "2020-09-08T21:39:26.573466-07:00", - "UpdatedAt": "2020-09-08T21:39:26.573466-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "available_spare", - "name": "Available Spare", - "value": 100, - "thresh": 10, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 99, - "CreatedAt": "2020-09-07T15:47:21.336981607Z", - "UpdatedAt": "2020-09-07T15:47:21.336981607Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "available_spare", - "name": "Available Spare", - "value": 100, - "thresh": 10, - "transformed_value": 0 - }, { - "ID": 83, - "CreatedAt": "2020-09-07T15:38:56.6335637Z", - "UpdatedAt": "2020-09-07T15:38:56.6335637Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "available_spare", - "name": "Available Spare", - "value": 100, - "thresh": 10, - "transformed_value": 0 - }, { - "ID": 67, - "CreatedAt": "2020-09-07T15:26:07.505182255Z", - "UpdatedAt": "2020-09-07T15:26:07.505182255Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "available_spare", - "name": "Available Spare", - "value": 100, - "thresh": 10, - "transformed_value": 0 - }, { - "ID": 51, - "CreatedAt": "2020-09-07T15:19:17.468100282Z", - "UpdatedAt": "2020-09-07T15:19:17.468100282Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "available_spare", - "name": "Available Spare", - "value": 100, - "thresh": 10, - "transformed_value": 0 - }, { - "ID": 35, - "CreatedAt": "2020-09-07T15:10:40.246339099Z", - "UpdatedAt": "2020-09-07T15:10:40.246339099Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "available_spare", - "name": "Available Spare", - "value": 100, - "thresh": 10, - "transformed_value": 0 - }, { - "ID": 19, - "CreatedAt": "2020-09-06T23:14:39.849394281Z", - "UpdatedAt": "2020-09-06T23:14:39.849394281Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "available_spare", - "name": "Available Spare", - "value": 100, - "thresh": 10, - "transformed_value": 0 - }, { - "ID": 3, - "CreatedAt": "2020-08-28T07:55:27.833551437Z", - "UpdatedAt": "2020-08-28T07:55:27.833551437Z", - "DeletedAt": null, - "smart_id": 4, - "attribute_id": "available_spare", - "name": "Available Spare", - "value": 100, - "thresh": 10, - "transformed_value": 0 - }] - }, { - "ID": 116, - "CreatedAt": "2020-09-08T21:39:26.57354-07:00", - "UpdatedAt": "2020-09-08T21:39:26.57354-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "percentage_used", - "name": "Percentage Used", - "value": 0, - "thresh": 100, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 100, - "CreatedAt": "2020-09-07T15:47:21.337060308Z", - "UpdatedAt": "2020-09-07T15:47:21.337060308Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "percentage_used", - "name": "Percentage Used", - "value": 0, - "thresh": 100, - "transformed_value": 0 - }, { - "ID": 84, - "CreatedAt": "2020-09-07T15:38:56.633637401Z", - "UpdatedAt": "2020-09-07T15:38:56.633637401Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "percentage_used", - "name": "Percentage Used", - "value": 0, - "thresh": 100, - "transformed_value": 0 - }, { - "ID": 68, - "CreatedAt": "2020-09-07T15:26:07.505262357Z", - "UpdatedAt": "2020-09-07T15:26:07.505262357Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "percentage_used", - "name": "Percentage Used", - "value": 0, - "thresh": 100, - "transformed_value": 0 - }, { - "ID": 52, - "CreatedAt": "2020-09-07T15:19:17.468187982Z", - "UpdatedAt": "2020-09-07T15:19:17.468187982Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "percentage_used", - "name": "Percentage Used", - "value": 0, - "thresh": 100, - "transformed_value": 0 - }, { - "ID": 36, - "CreatedAt": "2020-09-07T15:10:40.2464335Z", - "UpdatedAt": "2020-09-07T15:10:40.2464335Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "percentage_used", - "name": "Percentage Used", - "value": 0, - "thresh": 100, - "transformed_value": 0 - }, { - "ID": 20, - "CreatedAt": "2020-09-06T23:14:39.849473683Z", - "UpdatedAt": "2020-09-06T23:14:39.849473683Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "percentage_used", - "name": "Percentage Used", - "value": 0, - "thresh": 100, - "transformed_value": 0 - }, { - "ID": 4, - "CreatedAt": "2020-08-28T07:55:27.833639555Z", - "UpdatedAt": "2020-08-28T07:55:27.833639555Z", - "DeletedAt": null, - "smart_id": 4, - "attribute_id": "percentage_used", - "name": "Percentage Used", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 117, - "CreatedAt": "2020-09-08T21:39:26.573622-07:00", - "UpdatedAt": "2020-09-08T21:39:26.573622-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "data_units_read", - "name": "Data Units Read", - "value": 9511859, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 101, - "CreatedAt": "2020-09-07T15:47:21.337139008Z", - "UpdatedAt": "2020-09-07T15:47:21.337139008Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "data_units_read", - "name": "Data Units Read", - "value": 9511859, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 85, - "CreatedAt": "2020-09-07T15:38:56.633701001Z", - "UpdatedAt": "2020-09-07T15:38:56.633701001Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "data_units_read", - "name": "Data Units Read", - "value": 9511859, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 69, - "CreatedAt": "2020-09-07T15:26:07.505347059Z", - "UpdatedAt": "2020-09-07T15:26:07.505347059Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "data_units_read", - "name": "Data Units Read", - "value": 9511859, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 53, - "CreatedAt": "2020-09-07T15:19:17.468256482Z", - "UpdatedAt": "2020-09-07T15:19:17.468256482Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "data_units_read", - "name": "Data Units Read", - "value": 9511859, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 37, - "CreatedAt": "2020-09-07T15:10:40.2465052Z", - "UpdatedAt": "2020-09-07T15:10:40.2465052Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "data_units_read", - "name": "Data Units Read", - "value": 9511859, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 21, - "CreatedAt": "2020-09-06T23:14:39.849535985Z", - "UpdatedAt": "2020-09-06T23:14:39.849535985Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "data_units_read", - "name": "Data Units Read", - "value": 9511859, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 5, - "CreatedAt": "2020-08-28T07:55:27.833723448Z", - "UpdatedAt": "2020-08-28T07:55:27.833723448Z", - "DeletedAt": null, - "smart_id": 4, - "attribute_id": "data_units_read", - "name": "Data Units Read", - "value": 9511859, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 118, - "CreatedAt": "2020-09-08T21:39:26.57369-07:00", - "UpdatedAt": "2020-09-08T21:39:26.57369-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "data_units_written", - "name": "Data Units Written", - "value": 7773431, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 102, - "CreatedAt": "2020-09-07T15:47:21.337239108Z", - "UpdatedAt": "2020-09-07T15:47:21.337239108Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "data_units_written", - "name": "Data Units Written", - "value": 7773431, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 86, - "CreatedAt": "2020-09-07T15:38:56.633767202Z", - "UpdatedAt": "2020-09-07T15:38:56.633767202Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "data_units_written", - "name": "Data Units Written", - "value": 7773431, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 70, - "CreatedAt": "2020-09-07T15:26:07.505469162Z", - "UpdatedAt": "2020-09-07T15:26:07.505469162Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "data_units_written", - "name": "Data Units Written", - "value": 7773431, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 54, - "CreatedAt": "2020-09-07T15:19:17.468321982Z", - "UpdatedAt": "2020-09-07T15:19:17.468321982Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "data_units_written", - "name": "Data Units Written", - "value": 7773431, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 38, - "CreatedAt": "2020-09-07T15:10:40.246568201Z", - "UpdatedAt": "2020-09-07T15:10:40.246568201Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "data_units_written", - "name": "Data Units Written", - "value": 7773431, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 22, - "CreatedAt": "2020-09-06T23:14:39.849595287Z", - "UpdatedAt": "2020-09-06T23:14:39.849595287Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "data_units_written", - "name": "Data Units Written", - "value": 7773431, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 6, - "CreatedAt": "2020-08-28T07:55:27.833814267Z", - "UpdatedAt": "2020-08-28T07:55:27.833814267Z", - "DeletedAt": null, - "smart_id": 4, - "attribute_id": "data_units_written", - "name": "Data Units Written", - "value": 7773431, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 119, - "CreatedAt": "2020-09-08T21:39:26.573761-07:00", - "UpdatedAt": "2020-09-08T21:39:26.573761-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "host_reads", - "name": "Host Reads", - "value": 111303174, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 103, - "CreatedAt": "2020-09-07T15:47:21.337318208Z", - "UpdatedAt": "2020-09-07T15:47:21.337318208Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "host_reads", - "name": "Host Reads", - "value": 111303174, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 87, - "CreatedAt": "2020-09-07T15:38:56.633832703Z", - "UpdatedAt": "2020-09-07T15:38:56.633832703Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "host_reads", - "name": "Host Reads", - "value": 111303174, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 71, - "CreatedAt": "2020-09-07T15:26:07.505549465Z", - "UpdatedAt": "2020-09-07T15:26:07.505549465Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "host_reads", - "name": "Host Reads", - "value": 111303174, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 55, - "CreatedAt": "2020-09-07T15:19:17.468389981Z", - "UpdatedAt": "2020-09-07T15:19:17.468389981Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "host_reads", - "name": "Host Reads", - "value": 111303174, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 39, - "CreatedAt": "2020-09-07T15:10:40.246645901Z", - "UpdatedAt": "2020-09-07T15:10:40.246645901Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "host_reads", - "name": "Host Reads", - "value": 111303174, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 23, - "CreatedAt": "2020-09-06T23:14:39.849654489Z", - "UpdatedAt": "2020-09-06T23:14:39.849654489Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "host_reads", - "name": "Host Reads", - "value": 111303174, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 7, - "CreatedAt": "2020-08-28T07:55:27.833887571Z", - "UpdatedAt": "2020-08-28T07:55:27.833887571Z", - "DeletedAt": null, - "smart_id": 4, - "attribute_id": "host_reads", - "name": "Host Reads", - "value": 111303174, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 120, - "CreatedAt": "2020-09-08T21:39:26.573834-07:00", - "UpdatedAt": "2020-09-08T21:39:26.573834-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "host_writes", - "name": "Host Writes", - "value": 83170961, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 104, - "CreatedAt": "2020-09-07T15:47:21.337427308Z", - "UpdatedAt": "2020-09-07T15:47:21.337427308Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "host_writes", - "name": "Host Writes", - "value": 83170961, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 88, - "CreatedAt": "2020-09-07T15:38:56.633900603Z", - "UpdatedAt": "2020-09-07T15:38:56.633900603Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "host_writes", - "name": "Host Writes", - "value": 83170961, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 72, - "CreatedAt": "2020-09-07T15:26:07.505627267Z", - "UpdatedAt": "2020-09-07T15:26:07.505627267Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "host_writes", - "name": "Host Writes", - "value": 83170961, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 56, - "CreatedAt": "2020-09-07T15:19:17.468456681Z", - "UpdatedAt": "2020-09-07T15:19:17.468456681Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "host_writes", - "name": "Host Writes", - "value": 83170961, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 40, - "CreatedAt": "2020-09-07T15:10:40.246709102Z", - "UpdatedAt": "2020-09-07T15:10:40.246709102Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "host_writes", - "name": "Host Writes", - "value": 83170961, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 24, - "CreatedAt": "2020-09-06T23:14:39.849714291Z", - "UpdatedAt": "2020-09-06T23:14:39.849714291Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "host_writes", - "name": "Host Writes", - "value": 83170961, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 8, - "CreatedAt": "2020-08-28T07:55:27.833973719Z", - "UpdatedAt": "2020-08-28T07:55:27.833973719Z", - "DeletedAt": null, - "smart_id": 4, - "attribute_id": "host_writes", - "name": "Host Writes", - "value": 83170961, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 121, - "CreatedAt": "2020-09-08T21:39:26.5739-07:00", - "UpdatedAt": "2020-09-08T21:39:26.5739-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "controller_busy_time", - "name": "Controller Busy Time", - "value": 3060, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 105, - "CreatedAt": "2020-09-07T15:47:21.337516009Z", - "UpdatedAt": "2020-09-07T15:47:21.337516009Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "controller_busy_time", - "name": "Controller Busy Time", - "value": 3060, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 89, - "CreatedAt": "2020-09-07T15:38:56.633969604Z", - "UpdatedAt": "2020-09-07T15:38:56.633969604Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "controller_busy_time", - "name": "Controller Busy Time", - "value": 3060, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 73, - "CreatedAt": "2020-09-07T15:26:07.505724769Z", - "UpdatedAt": "2020-09-07T15:26:07.505724769Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "controller_busy_time", - "name": "Controller Busy Time", - "value": 3060, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 57, - "CreatedAt": "2020-09-07T15:19:17.468521581Z", - "UpdatedAt": "2020-09-07T15:19:17.468521581Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "controller_busy_time", - "name": "Controller Busy Time", - "value": 3060, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 41, - "CreatedAt": "2020-09-07T15:10:40.246774002Z", - "UpdatedAt": "2020-09-07T15:10:40.246774002Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "controller_busy_time", - "name": "Controller Busy Time", - "value": 3060, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 25, - "CreatedAt": "2020-09-06T23:14:39.849784693Z", - "UpdatedAt": "2020-09-06T23:14:39.849784693Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "controller_busy_time", - "name": "Controller Busy Time", - "value": 3060, - "thresh": 0, + "attrs": { + "available_spare": { + "attribute_id": "available_spare", + "name": "Available Spare", + "value": 100, + "thresh": 10, "transformed_value": 0 - }, { - "ID": 9, - "CreatedAt": "2020-08-28T07:55:27.834051665Z", - "UpdatedAt": "2020-08-28T07:55:27.834051665Z", - "DeletedAt": null, - "smart_id": 4, + }, + "controller_busy_time": { "attribute_id": "controller_busy_time", "name": "Controller Busy Time", "value": 3060, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 122, - "CreatedAt": "2020-09-08T21:39:26.573967-07:00", - "UpdatedAt": "2020-09-08T21:39:26.573967-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "power_cycles", - "name": "Power Cycles", - "value": 266, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 106, - "CreatedAt": "2020-09-07T15:47:21.337609809Z", - "UpdatedAt": "2020-09-07T15:47:21.337609809Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "power_cycles", - "name": "Power Cycles", - "value": 266, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 90, - "CreatedAt": "2020-09-07T15:38:56.634034304Z", - "UpdatedAt": "2020-09-07T15:38:56.634034304Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "power_cycles", - "name": "Power Cycles", - "value": 266, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 74, - "CreatedAt": "2020-09-07T15:26:07.505806272Z", - "UpdatedAt": "2020-09-07T15:26:07.505806272Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "power_cycles", - "name": "Power Cycles", - "value": 266, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 58, - "CreatedAt": "2020-09-07T15:19:17.468586181Z", - "UpdatedAt": "2020-09-07T15:19:17.468586181Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "power_cycles", - "name": "Power Cycles", - "value": 266, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 42, - "CreatedAt": "2020-09-07T15:10:40.246861903Z", - "UpdatedAt": "2020-09-07T15:10:40.246861903Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "power_cycles", - "name": "Power Cycles", - "value": 266, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 26, - "CreatedAt": "2020-09-06T23:14:39.849849495Z", - "UpdatedAt": "2020-09-06T23:14:39.849849495Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "power_cycles", - "name": "Power Cycles", - "value": 266, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 10, - "CreatedAt": "2020-08-28T07:55:27.834128174Z", - "UpdatedAt": "2020-08-28T07:55:27.834128174Z", - "DeletedAt": null, - "smart_id": 4, - "attribute_id": "power_cycles", - "name": "Power Cycles", - "value": 266, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 123, - "CreatedAt": "2020-09-08T21:39:26.57404-07:00", - "UpdatedAt": "2020-09-08T21:39:26.57404-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "power_on_hours", - "name": "Power on Hours", - "value": 2401, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 107, - "CreatedAt": "2020-09-07T15:47:21.337689109Z", - "UpdatedAt": "2020-09-07T15:47:21.337689109Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "power_on_hours", - "name": "Power on Hours", - "value": 2401, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 91, - "CreatedAt": "2020-09-07T15:38:56.634101905Z", - "UpdatedAt": "2020-09-07T15:38:56.634101905Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "power_on_hours", - "name": "Power on Hours", - "value": 2401, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 75, - "CreatedAt": "2020-09-07T15:26:07.505880974Z", - "UpdatedAt": "2020-09-07T15:26:07.505880974Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "power_on_hours", - "name": "Power on Hours", - "value": 2401, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 59, - "CreatedAt": "2020-09-07T15:19:17.468654081Z", - "UpdatedAt": "2020-09-07T15:19:17.468654081Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "power_on_hours", - "name": "Power on Hours", - "value": 2401, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 43, - "CreatedAt": "2020-09-07T15:10:40.246931403Z", - "UpdatedAt": "2020-09-07T15:10:40.246931403Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "power_on_hours", - "name": "Power on Hours", - "value": 2401, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 27, - "CreatedAt": "2020-09-06T23:14:39.849908596Z", - "UpdatedAt": "2020-09-06T23:14:39.849908596Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "power_on_hours", - "name": "Power on Hours", - "value": 2401, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 11, - "CreatedAt": "2020-08-28T07:55:27.834210433Z", - "UpdatedAt": "2020-08-28T07:55:27.834210433Z", - "DeletedAt": null, - "smart_id": 4, - "attribute_id": "power_on_hours", - "name": "Power on Hours", - "value": 2401, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 124, - "CreatedAt": "2020-09-08T21:39:26.574108-07:00", - "UpdatedAt": "2020-09-08T21:39:26.574108-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "unsafe_shutdowns", - "name": "Unsafe Shutdowns", - "value": 43, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 108, - "CreatedAt": "2020-09-07T15:47:21.337764809Z", - "UpdatedAt": "2020-09-07T15:47:21.337764809Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "unsafe_shutdowns", - "name": "Unsafe Shutdowns", - "value": 43, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 92, - "CreatedAt": "2020-09-07T15:38:56.634171906Z", - "UpdatedAt": "2020-09-07T15:38:56.634171906Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "unsafe_shutdowns", - "name": "Unsafe Shutdowns", - "value": 43, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 76, - "CreatedAt": "2020-09-07T15:26:07.505955776Z", - "UpdatedAt": "2020-09-07T15:26:07.505955776Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "unsafe_shutdowns", - "name": "Unsafe Shutdowns", - "value": 43, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 60, - "CreatedAt": "2020-09-07T15:19:17.46871948Z", - "UpdatedAt": "2020-09-07T15:19:17.46871948Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "unsafe_shutdowns", - "name": "Unsafe Shutdowns", - "value": 43, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 44, - "CreatedAt": "2020-09-07T15:10:40.247002504Z", - "UpdatedAt": "2020-09-07T15:10:40.247002504Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "unsafe_shutdowns", - "name": "Unsafe Shutdowns", - "value": 43, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 28, - "CreatedAt": "2020-09-06T23:14:39.849968798Z", - "UpdatedAt": "2020-09-06T23:14:39.849968798Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "unsafe_shutdowns", - "name": "Unsafe Shutdowns", - "value": 43, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 12, - "CreatedAt": "2020-08-28T07:55:27.834292136Z", - "UpdatedAt": "2020-08-28T07:55:27.834292136Z", - "DeletedAt": null, - "smart_id": 4, - "attribute_id": "unsafe_shutdowns", - "name": "Unsafe Shutdowns", - "value": 43, - "thresh": 0, + "thresh": -1, "transformed_value": 0 - }] - }, { - "ID": 125, - "CreatedAt": "2020-09-08T21:39:26.574178-07:00", - "UpdatedAt": "2020-09-08T21:39:26.574178-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "media_errors", - "name": "Media Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 109, - "CreatedAt": "2020-09-07T15:47:21.337839409Z", - "UpdatedAt": "2020-09-07T15:47:21.337839409Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "media_errors", - "name": "Media Errors", + }, + "critical_comp_time": { + "attribute_id": "critical_comp_time", + "name": "Critical CompTime", "value": 0, - "thresh": 0, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 93, - "CreatedAt": "2020-09-07T15:38:56.634234206Z", - "UpdatedAt": "2020-09-07T15:38:56.634234206Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "media_errors", - "name": "Media Errors", + }, + "critical_warning": { + "attribute_id": "critical_warning", + "name": "Critical Warning", "value": 0, "thresh": 0, "transformed_value": 0 - }, { - "ID": 77, - "CreatedAt": "2020-09-07T15:26:07.506062879Z", - "UpdatedAt": "2020-09-07T15:26:07.506062879Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "media_errors", - "name": "Media Errors", - "value": 0, - "thresh": 0, + }, + "data_units_read": { + "attribute_id": "data_units_read", + "name": "Data Units Read", + "value": 9511859, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 61, - "CreatedAt": "2020-09-07T15:19:17.46878678Z", - "UpdatedAt": "2020-09-07T15:19:17.46878678Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "media_errors", - "name": "Media Errors", - "value": 0, - "thresh": 0, + }, + "data_units_written": { + "attribute_id": "data_units_written", + "name": "Data Units Written", + "value": 7773431, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 45, - "CreatedAt": "2020-09-07T15:10:40.247110105Z", - "UpdatedAt": "2020-09-07T15:10:40.247110105Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "media_errors", - "name": "Media Errors", - "value": 0, - "thresh": 0, + }, + "host_reads": { + "attribute_id": "host_reads", + "name": "Host Reads", + "value": 111303174, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 29, - "CreatedAt": "2020-09-06T23:14:39.850046301Z", - "UpdatedAt": "2020-09-06T23:14:39.850046301Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "media_errors", - "name": "Media Errors", - "value": 0, - "thresh": 0, + }, + "host_writes": { + "attribute_id": "host_writes", + "name": "Host Writes", + "value": 83170961, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 13, - "CreatedAt": "2020-08-28T07:55:27.834373811Z", - "UpdatedAt": "2020-08-28T07:55:27.834373811Z", - "DeletedAt": null, - "smart_id": 4, + }, + "media_errors": { "attribute_id": "media_errors", "name": "Media Errors", "value": 0, "thresh": 0, "transformed_value": 0 - }] - }, { - "ID": 126, - "CreatedAt": "2020-09-08T21:39:26.574242-07:00", - "UpdatedAt": "2020-09-08T21:39:26.574242-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "num_err_log_entries", - "name": "Numb Err Log Entries", - "value": 0, - "thresh": 0, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 110, - "CreatedAt": "2020-09-07T15:47:21.337915109Z", - "UpdatedAt": "2020-09-07T15:47:21.337915109Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "num_err_log_entries", - "name": "Numb Err Log Entries", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 94, - "CreatedAt": "2020-09-07T15:38:56.634303007Z", - "UpdatedAt": "2020-09-07T15:38:56.634303007Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "num_err_log_entries", - "name": "Numb Err Log Entries", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 78, - "CreatedAt": "2020-09-07T15:26:07.506140681Z", - "UpdatedAt": "2020-09-07T15:26:07.506140681Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "num_err_log_entries", - "name": "Numb Err Log Entries", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 62, - "CreatedAt": "2020-09-07T15:19:17.46885548Z", - "UpdatedAt": "2020-09-07T15:19:17.46885548Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "num_err_log_entries", - "name": "Numb Err Log Entries", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 46, - "CreatedAt": "2020-09-07T15:10:40.247212006Z", - "UpdatedAt": "2020-09-07T15:10:40.247212006Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "num_err_log_entries", - "name": "Numb Err Log Entries", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 30, - "CreatedAt": "2020-09-06T23:14:39.850150504Z", - "UpdatedAt": "2020-09-06T23:14:39.850150504Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "num_err_log_entries", - "name": "Numb Err Log Entries", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 14, - "CreatedAt": "2020-08-28T07:55:27.834456493Z", - "UpdatedAt": "2020-08-28T07:55:27.834456493Z", - "DeletedAt": null, - "smart_id": 4, + }, + "num_err_log_entries": { "attribute_id": "num_err_log_entries", "name": "Numb Err Log Entries", "value": 0, "thresh": 0, "transformed_value": 0 - }] - }, { - "ID": 127, - "CreatedAt": "2020-09-08T21:39:26.574309-07:00", - "UpdatedAt": "2020-09-08T21:39:26.574309-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "warning_temp_time", - "name": "Warning Temp Time", - "value": 0, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 111, - "CreatedAt": "2020-09-07T15:47:21.33801171Z", - "UpdatedAt": "2020-09-07T15:47:21.33801171Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "warning_temp_time", - "name": "Warning Temp Time", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 95, - "CreatedAt": "2020-09-07T15:38:56.634377407Z", - "UpdatedAt": "2020-09-07T15:38:56.634377407Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "warning_temp_time", - "name": "Warning Temp Time", + }, + "percentage_used": { + "attribute_id": "percentage_used", + "name": "Percentage Used", "value": 0, - "thresh": 0, + "thresh": 100, "transformed_value": 0 - }, { - "ID": 79, - "CreatedAt": "2020-09-07T15:26:07.506214683Z", - "UpdatedAt": "2020-09-07T15:26:07.506214683Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "warning_temp_time", - "name": "Warning Temp Time", - "value": 0, - "thresh": 0, + }, + "power_cycles": { + "attribute_id": "power_cycles", + "name": "Power Cycles", + "value": 266, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 63, - "CreatedAt": "2020-09-07T15:19:17.468958879Z", - "UpdatedAt": "2020-09-07T15:19:17.468958879Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "warning_temp_time", - "name": "Warning Temp Time", - "value": 0, - "thresh": 0, + }, + "power_on_hours": { + "attribute_id": "power_on_hours", + "name": "Power on Hours", + "value": 2401, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 47, - "CreatedAt": "2020-09-07T15:10:40.247310706Z", - "UpdatedAt": "2020-09-07T15:10:40.247310706Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "warning_temp_time", - "name": "Warning Temp Time", - "value": 0, - "thresh": 0, + }, + "temperature": { + "attribute_id": "temperature", + "name": "Temperature", + "value": 36, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 31, - "CreatedAt": "2020-09-06T23:14:39.850219706Z", - "UpdatedAt": "2020-09-06T23:14:39.850219706Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "warning_temp_time", - "name": "Warning Temp Time", - "value": 0, - "thresh": 0, + }, + "unsafe_shutdowns": { + "attribute_id": "unsafe_shutdowns", + "name": "Unsafe Shutdowns", + "value": 43, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 15, - "CreatedAt": "2020-08-28T07:55:27.834538882Z", - "UpdatedAt": "2020-08-28T07:55:27.834538882Z", - "DeletedAt": null, - "smart_id": 4, + }, + "warning_temp_time": { "attribute_id": "warning_temp_time", "name": "Warning Temp Time", "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 128, - "CreatedAt": "2020-09-08T21:39:26.574383-07:00", - "UpdatedAt": "2020-09-08T21:39:26.574383-07:00", - "DeletedAt": null, - "smart_id": 46, - "attribute_id": "critical_comp_time", - "name": "Critical CompTime", - "value": 0, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 112, - "CreatedAt": "2020-09-07T15:47:21.33808201Z", - "UpdatedAt": "2020-09-07T15:47:21.33808201Z", - "DeletedAt": null, - "smart_id": 40, - "attribute_id": "critical_comp_time", - "name": "Critical CompTime", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 96, - "CreatedAt": "2020-09-07T15:38:56.634438008Z", - "UpdatedAt": "2020-09-07T15:38:56.634438008Z", - "DeletedAt": null, - "smart_id": 34, - "attribute_id": "critical_comp_time", - "name": "Critical CompTime", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 80, - "CreatedAt": "2020-09-07T15:26:07.506290585Z", - "UpdatedAt": "2020-09-07T15:26:07.506290585Z", - "DeletedAt": null, - "smart_id": 28, - "attribute_id": "critical_comp_time", - "name": "Critical CompTime", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 64, - "CreatedAt": "2020-09-07T15:19:17.469037079Z", - "UpdatedAt": "2020-09-07T15:19:17.469037079Z", - "DeletedAt": null, - "smart_id": 22, - "attribute_id": "critical_comp_time", - "name": "Critical CompTime", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 48, - "CreatedAt": "2020-09-07T15:10:40.247471107Z", - "UpdatedAt": "2020-09-07T15:10:40.247471107Z", - "DeletedAt": null, - "smart_id": 16, - "attribute_id": "critical_comp_time", - "name": "Critical CompTime", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 32, - "CreatedAt": "2020-09-06T23:14:39.850278807Z", - "UpdatedAt": "2020-09-06T23:14:39.850278807Z", - "DeletedAt": null, - "smart_id": 10, - "attribute_id": "critical_comp_time", - "name": "Critical CompTime", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 16, - "CreatedAt": "2020-08-28T07:55:27.834645921Z", - "UpdatedAt": "2020-08-28T07:55:27.834645921Z", - "DeletedAt": null, - "smart_id": 4, - "attribute_id": "critical_comp_time", - "name": "Critical CompTime", - "value": 0, - "thresh": 0, + "thresh": -1, "transformed_value": 0 - }] - }], - "scsi_attributes": [] + } + } }] - }, "metadata": { + }, + "metadata": { "available_spare": { "ideal": "high", "critical": true, @@ -1552,7 +224,12 @@ export const sda = { "description": "Contains the number of power-on hours. Power on hours is always logging, even when in low power mode.", "display_type": "" }, - "temperature": {"ideal": "", "critical": false, "description": "", "display_type": ""}, + "temperature": { + "ideal": "", + "critical": false, + "description": "", + "display_type": "" + }, "unsafe_shutdowns": { "ideal": "", "critical": false, @@ -1565,5 +242,6 @@ export const sda = { "description": "Contains the amount of time in minutes that the controller is operational and the Composite Temperature is greater than or equal to the Warning Composite Temperature Threshold (WCTEMP) field and less than the Critical Composite Temperature Threshold (CCTEMP) field in the Identify Controller data structure.", "display_type": "" } - }, "success": true + }, + "success": true } diff --git a/webapp/frontend/src/app/data/mock/device/details/sdb.ts b/webapp/frontend/src/app/data/mock/device/details/sdb.ts index e6b3771..e658e79 100644 --- a/webapp/frontend/src/app/data/mock/device/details/sdb.ts +++ b/webapp/frontend/src/app/data/mock/device/details/sdb.ts @@ -1,4406 +1,651 @@ export const sdb = { "data": { - "CreatedAt": "2020-08-28T07:55:27.755292213Z", - "UpdatedAt": "2020-09-08T21:39:26.56453-07:00", - "DeletedAt": null, - "wwn": "0x5000cca264eb01d7", - "device_name": "sdb", - "manufacturer": "ATA", - "model_name": "WDC_WD140EDFZ-11A0VA0", - "interface_type": "SCSI", - "interface_speed": "6.0 Gb/s", - "serial_number": "9RK1XXXXX", - "firmware": "81.00A81", - "rotational_speed": 5400, - "capacity": 14000519643136, - "form_factor": "3.5 inches", - "smart_support": false, - "device_protocol": "ATA", - "device_type": "sat", - "smart_results": [{ - "ID": 44, - "CreatedAt": "2020-09-08T21:39:26.565492-07:00", - "UpdatedAt": "2020-09-08T21:39:26.565492-07:00", + "device": { + "CreatedAt": "2021-06-24T21:17:31.302191-07:00", + "UpdatedAt": "2021-06-27T09:25:21.627183-07:00", "DeletedAt": null, + "wwn": "0x5000cca264eb01d7", + "device_name": "sdb", + "manufacturer": "ATA", + "model_name": "WDC_WD140EDFZ-11A0VA0", + "interface_type": "SCSI", + "interface_speed": "", + "serial_number": "9RK1XXXXX", + "firmware": "81.00A81", + "rotational_speed": 0, + "capacity": 14000519643136, + "form_factor": "", + "smart_support": false, + "device_protocol": "ATA", + "device_type": "", + "label": "", + "host_id": "", + "device_status": 0 + }, + "smart_results": [{ + "date": "2020-06-21T00:03:30Z", "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-20T17:03:30-07:00", - "smart_status": "passed", + "device_protocol": "ATA", "temp": 32, "power_on_hours": 1730, "power_cycle_count": 9, - "ata_attributes": [{ - "ID": 390, - "CreatedAt": "2020-09-08T21:39:26.565859-07:00", - "UpdatedAt": "2020-09-08T21:39:26.565859-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.034155719633986996, - "history": [{ - "ID": 372, - "CreatedAt": "2020-09-08T21:39:26.554625-07:00", - "UpdatedAt": "2020-09-08T21:39:26.554625-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 337, - "CreatedAt": "2020-09-07T15:47:21.319715469Z", - "UpdatedAt": "2020-09-07T15:47:21.319715469Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 319, - "CreatedAt": "2020-09-07T15:47:21.30624404Z", - "UpdatedAt": "2020-09-07T15:47:21.30624404Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 284, - "CreatedAt": "2020-09-07T15:38:56.621607095Z", - "UpdatedAt": "2020-09-07T15:38:56.621607095Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 266, - "CreatedAt": "2020-09-07T15:38:56.608981483Z", - "UpdatedAt": "2020-09-07T15:38:56.608981483Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 231, - "CreatedAt": "2020-09-07T15:26:07.492775316Z", - "UpdatedAt": "2020-09-07T15:26:07.492775316Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 213, - "CreatedAt": "2020-09-07T15:26:07.479127343Z", - "UpdatedAt": "2020-09-07T15:26:07.479127343Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 178, - "CreatedAt": "2020-09-07T15:19:17.454721127Z", - "UpdatedAt": "2020-09-07T15:19:17.454721127Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 160, - "CreatedAt": "2020-09-07T15:19:17.441278472Z", - "UpdatedAt": "2020-09-07T15:19:17.441278472Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 125, - "CreatedAt": "2020-09-07T15:10:40.234375512Z", - "UpdatedAt": "2020-09-07T15:10:40.234375512Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 107, - "CreatedAt": "2020-09-07T15:10:40.221903021Z", - "UpdatedAt": "2020-09-07T15:10:40.221903021Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 72, - "CreatedAt": "2020-09-06T23:14:39.838774963Z", - "UpdatedAt": "2020-09-06T23:14:39.838774963Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 54, - "CreatedAt": "2020-09-06T23:14:39.828352851Z", - "UpdatedAt": "2020-09-06T23:14:39.828352851Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 19, - "CreatedAt": "2020-08-28T07:55:27.811031219Z", - "UpdatedAt": "2020-08-28T07:55:27.811031219Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 1, - "CreatedAt": "2020-08-28T07:55:27.793568936Z", - "UpdatedAt": "2020-08-28T07:55:27.793568936Z", - "DeletedAt": null, - "smart_id": 1, + "attrs": { + "1": { "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 391, - "CreatedAt": "2020-09-08T21:39:26.566009-07:00", - "UpdatedAt": "2020-09-08T21:39:26.566009-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 373, - "CreatedAt": "2020-09-08T21:39:26.555538-07:00", - "UpdatedAt": "2020-09-08T21:39:26.555538-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 338, - "CreatedAt": "2020-09-07T15:47:21.31987157Z", - "UpdatedAt": "2020-09-07T15:47:21.31987157Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 320, - "CreatedAt": "2020-09-07T15:47:21.30639844Z", - "UpdatedAt": "2020-09-07T15:47:21.30639844Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 285, - "CreatedAt": "2020-09-07T15:38:56.621740196Z", - "UpdatedAt": "2020-09-07T15:38:56.621740196Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 267, - "CreatedAt": "2020-09-07T15:38:56.609155985Z", - "UpdatedAt": "2020-09-07T15:38:56.609155985Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 232, - "CreatedAt": "2020-09-07T15:26:07.49293042Z", - "UpdatedAt": "2020-09-07T15:26:07.49293042Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 214, - "CreatedAt": "2020-09-07T15:26:07.479321549Z", - "UpdatedAt": "2020-09-07T15:26:07.479321549Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 179, - "CreatedAt": "2020-09-07T15:19:17.454872527Z", - "UpdatedAt": "2020-09-07T15:19:17.454872527Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 161, - "CreatedAt": "2020-09-07T15:19:17.441578271Z", - "UpdatedAt": "2020-09-07T15:19:17.441578271Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 126, - "CreatedAt": "2020-09-07T15:10:40.234501713Z", - "UpdatedAt": "2020-09-07T15:10:40.234501713Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 108, - "CreatedAt": "2020-09-07T15:10:40.222051722Z", - "UpdatedAt": "2020-09-07T15:10:40.222051722Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 73, - "CreatedAt": "2020-09-06T23:14:39.838895667Z", - "UpdatedAt": "2020-09-06T23:14:39.838895667Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 55, - "CreatedAt": "2020-09-06T23:14:39.828477555Z", - "UpdatedAt": "2020-09-06T23:14:39.828477555Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 20, - "CreatedAt": "2020-08-28T07:55:27.81120328Z", - "UpdatedAt": "2020-08-28T07:55:27.81120328Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 2, - "CreatedAt": "2020-08-28T07:55:27.793695119Z", - "UpdatedAt": "2020-08-28T07:55:27.793695119Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "worst": 135, - "thresh": 54, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 392, - "CreatedAt": "2020-09-08T21:39:26.566086-07:00", - "UpdatedAt": "2020-09-08T21:39:26.566086-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0, - "status": "warn", - "status_reason": "Observed Failure Rate for Attribute is greater than 10%", - "failure_rate": 0.11452195377351217, - "history": [{ - "ID": 374, - "CreatedAt": "2020-09-08T21:39:26.555647-07:00", - "UpdatedAt": "2020-09-08T21:39:26.555647-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 339, - "CreatedAt": "2020-09-07T15:47:21.31996407Z", - "UpdatedAt": "2020-09-07T15:47:21.31996407Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 321, - "CreatedAt": "2020-09-07T15:47:21.30649104Z", - "UpdatedAt": "2020-09-07T15:47:21.30649104Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 286, - "CreatedAt": "2020-09-07T15:38:56.621825497Z", - "UpdatedAt": "2020-09-07T15:38:56.621825497Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 268, - "CreatedAt": "2020-09-07T15:38:56.609869491Z", - "UpdatedAt": "2020-09-07T15:38:56.609869491Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 233, - "CreatedAt": "2020-09-07T15:26:07.493026823Z", - "UpdatedAt": "2020-09-07T15:26:07.493026823Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 215, - "CreatedAt": "2020-09-07T15:26:07.479457552Z", - "UpdatedAt": "2020-09-07T15:26:07.479457552Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 180, - "CreatedAt": "2020-09-07T15:19:17.454960826Z", - "UpdatedAt": "2020-09-07T15:19:17.454960826Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 162, - "CreatedAt": "2020-09-07T15:19:17.441750771Z", - "UpdatedAt": "2020-09-07T15:19:17.441750771Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 127, - "CreatedAt": "2020-09-07T15:10:40.234580613Z", - "UpdatedAt": "2020-09-07T15:10:40.234580613Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 109, - "CreatedAt": "2020-09-07T15:10:40.222249924Z", - "UpdatedAt": "2020-09-07T15:10:40.222249924Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 74, - "CreatedAt": "2020-09-06T23:14:39.838970169Z", - "UpdatedAt": "2020-09-06T23:14:39.838970169Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 56, - "CreatedAt": "2020-09-06T23:14:39.828556257Z", - "UpdatedAt": "2020-09-06T23:14:39.828556257Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 21, - "CreatedAt": "2020-08-28T07:55:27.811301517Z", - "UpdatedAt": "2020-08-28T07:55:27.811301517Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 3, - "CreatedAt": "2020-08-28T07:55:27.793803735Z", - "UpdatedAt": "2020-08-28T07:55:27.793803735Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "worst": 81, - "thresh": 1, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 393, - "CreatedAt": "2020-09-08T21:39:26.56616-07:00", - "UpdatedAt": "2020-09-08T21:39:26.56616-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.01989335424860646, - "history": [{ - "ID": 375, - "CreatedAt": "2020-09-08T21:39:26.555728-07:00", - "UpdatedAt": "2020-09-08T21:39:26.555728-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 340, - "CreatedAt": "2020-09-07T15:47:21.32004967Z", - "UpdatedAt": "2020-09-07T15:47:21.32004967Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 322, - "CreatedAt": "2020-09-07T15:47:21.30657324Z", - "UpdatedAt": "2020-09-07T15:47:21.30657324Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 287, - "CreatedAt": "2020-09-07T15:38:56.621906897Z", - "UpdatedAt": "2020-09-07T15:38:56.621906897Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 269, - "CreatedAt": "2020-09-07T15:38:56.609959692Z", - "UpdatedAt": "2020-09-07T15:38:56.609959692Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 234, - "CreatedAt": "2020-09-07T15:26:07.493143826Z", - "UpdatedAt": "2020-09-07T15:26:07.493143826Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 216, - "CreatedAt": "2020-09-07T15:26:07.479584956Z", - "UpdatedAt": "2020-09-07T15:26:07.479584956Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 181, - "CreatedAt": "2020-09-07T15:19:17.455045926Z", - "UpdatedAt": "2020-09-07T15:19:17.455045926Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 163, - "CreatedAt": "2020-09-07T15:19:17.442228869Z", - "UpdatedAt": "2020-09-07T15:19:17.442228869Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 128, - "CreatedAt": "2020-09-07T15:10:40.234652914Z", - "UpdatedAt": "2020-09-07T15:10:40.234652914Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 110, - "CreatedAt": "2020-09-07T15:10:40.222378024Z", - "UpdatedAt": "2020-09-07T15:10:40.222378024Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 75, - "CreatedAt": "2020-09-06T23:14:39.839060472Z", - "UpdatedAt": "2020-09-06T23:14:39.839060472Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 57, - "CreatedAt": "2020-09-06T23:14:39.82862886Z", - "UpdatedAt": "2020-09-06T23:14:39.82862886Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 22, - "CreatedAt": "2020-08-28T07:55:27.811385053Z", - "UpdatedAt": "2020-08-28T07:55:27.811385053Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 4, - "CreatedAt": "2020-08-28T07:55:27.79389462Z", - "UpdatedAt": "2020-08-28T07:55:27.79389462Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 394, - "CreatedAt": "2020-09-08T21:39:26.566242-07:00", - "UpdatedAt": "2020-09-08T21:39:26.566242-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.025169175350572493, - "history": [{ - "ID": 376, - "CreatedAt": "2020-09-08T21:39:26.555865-07:00", - "UpdatedAt": "2020-09-08T21:39:26.555865-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 341, - "CreatedAt": "2020-09-07T15:47:21.32013207Z", - "UpdatedAt": "2020-09-07T15:47:21.32013207Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 323, - "CreatedAt": "2020-09-07T15:47:21.306652041Z", - "UpdatedAt": "2020-09-07T15:47:21.306652041Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 288, - "CreatedAt": "2020-09-07T15:38:56.621982198Z", - "UpdatedAt": "2020-09-07T15:38:56.621982198Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 270, - "CreatedAt": "2020-09-07T15:38:56.610037693Z", - "UpdatedAt": "2020-09-07T15:38:56.610037693Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 235, - "CreatedAt": "2020-09-07T15:26:07.493235628Z", - "UpdatedAt": "2020-09-07T15:26:07.493235628Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 217, - "CreatedAt": "2020-09-07T15:26:07.479976967Z", - "UpdatedAt": "2020-09-07T15:26:07.479976967Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 182, - "CreatedAt": "2020-09-07T15:19:17.455121626Z", - "UpdatedAt": "2020-09-07T15:19:17.455121626Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 164, - "CreatedAt": "2020-09-07T15:19:17.442543768Z", - "UpdatedAt": "2020-09-07T15:19:17.442543768Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 129, - "CreatedAt": "2020-09-07T15:10:40.234722314Z", - "UpdatedAt": "2020-09-07T15:10:40.234722314Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 111, - "CreatedAt": "2020-09-07T15:10:40.222455425Z", - "UpdatedAt": "2020-09-07T15:10:40.222455425Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 76, - "CreatedAt": "2020-09-06T23:14:39.839234477Z", - "UpdatedAt": "2020-09-06T23:14:39.839234477Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 58, - "CreatedAt": "2020-09-06T23:14:39.828698262Z", - "UpdatedAt": "2020-09-06T23:14:39.828698262Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 23, - "CreatedAt": "2020-08-28T07:55:27.811468471Z", - "UpdatedAt": "2020-08-28T07:55:27.811468471Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 5, - "CreatedAt": "2020-08-28T07:55:27.793989682Z", - "UpdatedAt": "2020-08-28T07:55:27.793989682Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 395, - "CreatedAt": "2020-09-08T21:39:26.566309-07:00", - "UpdatedAt": "2020-09-08T21:39:26.566309-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.01087335627722523, - "history": [{ - "ID": 377, - "CreatedAt": "2020-09-08T21:39:26.555941-07:00", - "UpdatedAt": "2020-09-08T21:39:26.555941-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 342, - "CreatedAt": "2020-09-07T15:47:21.320264671Z", - "UpdatedAt": "2020-09-07T15:47:21.320264671Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 324, - "CreatedAt": "2020-09-07T15:47:21.307035342Z", - "UpdatedAt": "2020-09-07T15:47:21.307035342Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 289, - "CreatedAt": "2020-09-07T15:38:56.622059399Z", - "UpdatedAt": "2020-09-07T15:38:56.622059399Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 271, - "CreatedAt": "2020-09-07T15:38:56.610108993Z", - "UpdatedAt": "2020-09-07T15:38:56.610108993Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 236, - "CreatedAt": "2020-09-07T15:26:07.493371532Z", - "UpdatedAt": "2020-09-07T15:26:07.493371532Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 218, - "CreatedAt": "2020-09-07T15:26:07.480271875Z", - "UpdatedAt": "2020-09-07T15:26:07.480271875Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 183, - "CreatedAt": "2020-09-07T15:19:17.455196926Z", - "UpdatedAt": "2020-09-07T15:19:17.455196926Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 165, - "CreatedAt": "2020-09-07T15:19:17.442652368Z", - "UpdatedAt": "2020-09-07T15:19:17.442652368Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 130, - "CreatedAt": "2020-09-07T15:10:40.234829815Z", - "UpdatedAt": "2020-09-07T15:10:40.234829815Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 112, - "CreatedAt": "2020-09-07T15:10:40.222525726Z", - "UpdatedAt": "2020-09-07T15:10:40.222525726Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 77, - "CreatedAt": "2020-09-06T23:14:39.839317879Z", - "UpdatedAt": "2020-09-06T23:14:39.839317879Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 59, - "CreatedAt": "2020-09-06T23:14:39.828766564Z", - "UpdatedAt": "2020-09-06T23:14:39.828766564Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 24, - "CreatedAt": "2020-08-28T07:55:27.811550965Z", - "UpdatedAt": "2020-08-28T07:55:27.811550965Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 6, - "CreatedAt": "2020-08-28T07:55:27.794077393Z", - "UpdatedAt": "2020-08-28T07:55:27.794077393Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 396, - "CreatedAt": "2020-09-08T21:39:26.566388-07:00", - "UpdatedAt": "2020-09-08T21:39:26.566388-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 378, - "CreatedAt": "2020-09-08T21:39:26.556011-07:00", - "UpdatedAt": "2020-09-08T21:39:26.556011-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 343, - "CreatedAt": "2020-09-07T15:47:21.320351671Z", - "UpdatedAt": "2020-09-07T15:47:21.320351671Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 325, - "CreatedAt": "2020-09-07T15:47:21.307191042Z", - "UpdatedAt": "2020-09-07T15:47:21.307191042Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 290, - "CreatedAt": "2020-09-07T15:38:56.622135099Z", - "UpdatedAt": "2020-09-07T15:38:56.622135099Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 272, - "CreatedAt": "2020-09-07T15:38:56.610177694Z", - "UpdatedAt": "2020-09-07T15:38:56.610177694Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 237, - "CreatedAt": "2020-09-07T15:26:07.493474635Z", - "UpdatedAt": "2020-09-07T15:26:07.493474635Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 219, - "CreatedAt": "2020-09-07T15:26:07.480369577Z", - "UpdatedAt": "2020-09-07T15:26:07.480369577Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 184, - "CreatedAt": "2020-09-07T15:19:17.455270825Z", - "UpdatedAt": "2020-09-07T15:19:17.455270825Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 166, - "CreatedAt": "2020-09-07T15:19:17.442737567Z", - "UpdatedAt": "2020-09-07T15:19:17.442737567Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 131, - "CreatedAt": "2020-09-07T15:10:40.234912916Z", - "UpdatedAt": "2020-09-07T15:10:40.234912916Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 113, - "CreatedAt": "2020-09-07T15:10:40.222607826Z", - "UpdatedAt": "2020-09-07T15:10:40.222607826Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 78, - "CreatedAt": "2020-09-06T23:14:39.839390682Z", - "UpdatedAt": "2020-09-06T23:14:39.839390682Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 60, - "CreatedAt": "2020-09-06T23:14:39.828832166Z", - "UpdatedAt": "2020-09-06T23:14:39.828832166Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 25, - "CreatedAt": "2020-08-28T07:55:27.811628355Z", - "UpdatedAt": "2020-08-28T07:55:27.811628355Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 7, - "CreatedAt": "2020-08-28T07:55:27.794167288Z", - "UpdatedAt": "2020-08-28T07:55:27.794167288Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "worst": 133, - "thresh": 20, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 397, - "CreatedAt": "2020-09-08T21:39:26.566454-07:00", - "UpdatedAt": "2020-09-08T21:39:26.566454-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 379, - "CreatedAt": "2020-09-08T21:39:26.556082-07:00", - "UpdatedAt": "2020-09-08T21:39:26.556082-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 344, - "CreatedAt": "2020-09-07T15:47:21.320434771Z", - "UpdatedAt": "2020-09-07T15:47:21.320434771Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 326, - "CreatedAt": "2020-09-07T15:47:21.307320542Z", - "UpdatedAt": "2020-09-07T15:47:21.307320542Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 291, - "CreatedAt": "2020-09-07T15:38:56.622211Z", - "UpdatedAt": "2020-09-07T15:38:56.622211Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 273, - "CreatedAt": "2020-09-07T15:38:56.610246595Z", - "UpdatedAt": "2020-09-07T15:38:56.610246595Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 238, - "CreatedAt": "2020-09-07T15:26:07.493636539Z", - "UpdatedAt": "2020-09-07T15:26:07.493636539Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 220, - "CreatedAt": "2020-09-07T15:26:07.48045858Z", - "UpdatedAt": "2020-09-07T15:26:07.48045858Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 185, - "CreatedAt": "2020-09-07T15:19:17.455349925Z", - "UpdatedAt": "2020-09-07T15:19:17.455349925Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 167, - "CreatedAt": "2020-09-07T15:19:17.442814567Z", - "UpdatedAt": "2020-09-07T15:19:17.442814567Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 132, - "CreatedAt": "2020-09-07T15:10:40.235014517Z", - "UpdatedAt": "2020-09-07T15:10:40.235014517Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 114, - "CreatedAt": "2020-09-07T15:10:40.222673127Z", - "UpdatedAt": "2020-09-07T15:10:40.222673127Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 79, - "CreatedAt": "2020-09-06T23:14:39.839467884Z", - "UpdatedAt": "2020-09-06T23:14:39.839467884Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 61, - "CreatedAt": "2020-09-06T23:14:39.828900468Z", - "UpdatedAt": "2020-09-06T23:14:39.828900468Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 26, - "CreatedAt": "2020-08-28T07:55:27.8117049Z", - "UpdatedAt": "2020-08-28T07:55:27.8117049Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 8, - "CreatedAt": "2020-08-28T07:55:27.794251087Z", - "UpdatedAt": "2020-08-28T07:55:27.794251087Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 398, - "CreatedAt": "2020-09-08T21:39:26.566526-07:00", - "UpdatedAt": "2020-09-08T21:39:26.566526-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.05459827163896099, - "history": [{ - "ID": 380, - "CreatedAt": "2020-09-08T21:39:26.556157-07:00", - "UpdatedAt": "2020-09-08T21:39:26.556157-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 345, - "CreatedAt": "2020-09-07T15:47:21.320529071Z", - "UpdatedAt": "2020-09-07T15:47:21.320529071Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 327, - "CreatedAt": "2020-09-07T15:47:21.307449642Z", - "UpdatedAt": "2020-09-07T15:47:21.307449642Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 292, - "CreatedAt": "2020-09-07T15:38:56.622285101Z", - "UpdatedAt": "2020-09-07T15:38:56.622285101Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 274, - "CreatedAt": "2020-09-07T15:38:56.610358696Z", - "UpdatedAt": "2020-09-07T15:38:56.610358696Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 239, - "CreatedAt": "2020-09-07T15:26:07.493765343Z", - "UpdatedAt": "2020-09-07T15:26:07.493765343Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 221, - "CreatedAt": "2020-09-07T15:26:07.480546682Z", - "UpdatedAt": "2020-09-07T15:26:07.480546682Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 186, - "CreatedAt": "2020-09-07T15:19:17.455425525Z", - "UpdatedAt": "2020-09-07T15:19:17.455425525Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 168, - "CreatedAt": "2020-09-07T15:19:17.442892767Z", - "UpdatedAt": "2020-09-07T15:19:17.442892767Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 133, - "CreatedAt": "2020-09-07T15:10:40.235101017Z", - "UpdatedAt": "2020-09-07T15:10:40.235101017Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 115, - "CreatedAt": "2020-09-07T15:10:40.222780027Z", - "UpdatedAt": "2020-09-07T15:10:40.222780027Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 80, - "CreatedAt": "2020-09-06T23:14:39.839545886Z", - "UpdatedAt": "2020-09-06T23:14:39.839545886Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 62, - "CreatedAt": "2020-09-06T23:14:39.82896797Z", - "UpdatedAt": "2020-09-06T23:14:39.82896797Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 27, - "CreatedAt": "2020-08-28T07:55:27.81178263Z", - "UpdatedAt": "2020-08-28T07:55:27.81178263Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 9, - "CreatedAt": "2020-08-28T07:55:27.794343259Z", - "UpdatedAt": "2020-08-28T07:55:27.794343259Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 1, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 399, - "CreatedAt": "2020-09-08T21:39:26.566594-07:00", - "UpdatedAt": "2020-09-08T21:39:26.566594-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.019835987118930823, - "history": [{ - "ID": 381, - "CreatedAt": "2020-09-08T21:39:26.556225-07:00", - "UpdatedAt": "2020-09-08T21:39:26.556225-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 346, - "CreatedAt": "2020-09-07T15:47:21.320607871Z", - "UpdatedAt": "2020-09-07T15:47:21.320607871Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 328, - "CreatedAt": "2020-09-07T15:47:21.307575143Z", - "UpdatedAt": "2020-09-07T15:47:21.307575143Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 293, - "CreatedAt": "2020-09-07T15:38:56.622436802Z", - "UpdatedAt": "2020-09-07T15:38:56.622436802Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 275, - "CreatedAt": "2020-09-07T15:38:56.610431596Z", - "UpdatedAt": "2020-09-07T15:38:56.610431596Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 240, - "CreatedAt": "2020-09-07T15:26:07.493897347Z", - "UpdatedAt": "2020-09-07T15:26:07.493897347Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 222, - "CreatedAt": "2020-09-07T15:26:07.480631784Z", - "UpdatedAt": "2020-09-07T15:26:07.480631784Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 187, - "CreatedAt": "2020-09-07T15:19:17.455500025Z", - "UpdatedAt": "2020-09-07T15:19:17.455500025Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 169, - "CreatedAt": "2020-09-07T15:19:17.442969566Z", - "UpdatedAt": "2020-09-07T15:19:17.442969566Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 134, - "CreatedAt": "2020-09-07T15:10:40.23543132Z", - "UpdatedAt": "2020-09-07T15:10:40.23543132Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 116, - "CreatedAt": "2020-09-07T15:10:40.222855428Z", - "UpdatedAt": "2020-09-07T15:10:40.222855428Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 81, - "CreatedAt": "2020-09-06T23:14:39.839623189Z", - "UpdatedAt": "2020-09-06T23:14:39.839623189Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 63, - "CreatedAt": "2020-09-06T23:14:39.829035472Z", - "UpdatedAt": "2020-09-06T23:14:39.829035472Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 28, - "CreatedAt": "2020-08-28T07:55:27.811864251Z", - "UpdatedAt": "2020-08-28T07:55:27.811864251Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 10, - "CreatedAt": "2020-08-28T07:55:27.79442562Z", - "UpdatedAt": "2020-08-28T07:55:27.79442562Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 400, - "CreatedAt": "2020-09-08T21:39:26.566661-07:00", - "UpdatedAt": "2020-09-08T21:39:26.566661-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 382, - "CreatedAt": "2020-09-08T21:39:26.556294-07:00", - "UpdatedAt": "2020-09-08T21:39:26.556294-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 347, - "CreatedAt": "2020-09-07T15:47:21.320688272Z", - "UpdatedAt": "2020-09-07T15:47:21.320688272Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 329, - "CreatedAt": "2020-09-07T15:47:21.307698843Z", - "UpdatedAt": "2020-09-07T15:47:21.307698843Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 294, - "CreatedAt": "2020-09-07T15:38:56.622559903Z", - "UpdatedAt": "2020-09-07T15:38:56.622559903Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 276, - "CreatedAt": "2020-09-07T15:38:56.610502597Z", - "UpdatedAt": "2020-09-07T15:38:56.610502597Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 241, - "CreatedAt": "2020-09-07T15:26:07.493985749Z", - "UpdatedAt": "2020-09-07T15:26:07.493985749Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 223, - "CreatedAt": "2020-09-07T15:26:07.480743187Z", - "UpdatedAt": "2020-09-07T15:26:07.480743187Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 188, - "CreatedAt": "2020-09-07T15:19:17.455575224Z", - "UpdatedAt": "2020-09-07T15:19:17.455575224Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 170, - "CreatedAt": "2020-09-07T15:19:17.443042566Z", - "UpdatedAt": "2020-09-07T15:19:17.443042566Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 135, - "CreatedAt": "2020-09-07T15:10:40.23553022Z", - "UpdatedAt": "2020-09-07T15:10:40.23553022Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 117, - "CreatedAt": "2020-09-07T15:10:40.222932429Z", - "UpdatedAt": "2020-09-07T15:10:40.222932429Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 82, - "CreatedAt": "2020-09-06T23:14:39.839696091Z", - "UpdatedAt": "2020-09-06T23:14:39.839696091Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 64, - "CreatedAt": "2020-09-06T23:14:39.829103574Z", - "UpdatedAt": "2020-09-06T23:14:39.829103574Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 29, - "CreatedAt": "2020-08-28T07:55:27.811945021Z", - "UpdatedAt": "2020-08-28T07:55:27.811945021Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 11, - "CreatedAt": "2020-08-28T07:55:27.794526672Z", - "UpdatedAt": "2020-08-28T07:55:27.794526672Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "worst": 100, - "thresh": 25, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 401, - "CreatedAt": "2020-09-08T21:39:26.566727-07:00", - "UpdatedAt": "2020-09-08T21:39:26.566727-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.01634692899031039, - "history": [{ - "ID": 383, - "CreatedAt": "2020-09-08T21:39:26.556363-07:00", - "UpdatedAt": "2020-09-08T21:39:26.556363-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 348, - "CreatedAt": "2020-09-07T15:47:21.320764972Z", - "UpdatedAt": "2020-09-07T15:47:21.320764972Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 330, - "CreatedAt": "2020-09-07T15:47:21.308110544Z", - "UpdatedAt": "2020-09-07T15:47:21.308110544Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 295, - "CreatedAt": "2020-09-07T15:38:56.622638304Z", - "UpdatedAt": "2020-09-07T15:38:56.622638304Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 277, - "CreatedAt": "2020-09-07T15:38:56.610569797Z", - "UpdatedAt": "2020-09-07T15:38:56.610569797Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 242, - "CreatedAt": "2020-09-07T15:26:07.494076151Z", - "UpdatedAt": "2020-09-07T15:26:07.494076151Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 224, - "CreatedAt": "2020-09-07T15:26:07.48083529Z", - "UpdatedAt": "2020-09-07T15:26:07.48083529Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 189, - "CreatedAt": "2020-09-07T15:19:17.455652324Z", - "UpdatedAt": "2020-09-07T15:19:17.455652324Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 171, - "CreatedAt": "2020-09-07T15:19:17.443115666Z", - "UpdatedAt": "2020-09-07T15:19:17.443115666Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 136, - "CreatedAt": "2020-09-07T15:10:40.235693822Z", - "UpdatedAt": "2020-09-07T15:10:40.235693822Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 118, - "CreatedAt": "2020-09-07T15:10:40.223005329Z", - "UpdatedAt": "2020-09-07T15:10:40.223005329Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 83, - "CreatedAt": "2020-09-06T23:14:39.839769893Z", - "UpdatedAt": "2020-09-06T23:14:39.839769893Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 65, - "CreatedAt": "2020-09-06T23:14:39.829170476Z", - "UpdatedAt": "2020-09-06T23:14:39.829170476Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 30, - "CreatedAt": "2020-08-28T07:55:27.812020236Z", - "UpdatedAt": "2020-08-28T07:55:27.812020236Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 12, - "CreatedAt": "2020-08-28T07:55:27.794617502Z", - "UpdatedAt": "2020-08-28T07:55:27.794617502Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 402, - "CreatedAt": "2020-09-08T21:39:26.566795-07:00", - "UpdatedAt": "2020-09-08T21:39:26.566795-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 384, - "CreatedAt": "2020-09-08T21:39:26.556431-07:00", - "UpdatedAt": "2020-09-08T21:39:26.556431-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 349, - "CreatedAt": "2020-09-07T15:47:21.320843672Z", - "UpdatedAt": "2020-09-07T15:47:21.320843672Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 331, - "CreatedAt": "2020-09-07T15:47:21.308263444Z", - "UpdatedAt": "2020-09-07T15:47:21.308263444Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 296, - "CreatedAt": "2020-09-07T15:38:56.622711005Z", - "UpdatedAt": "2020-09-07T15:38:56.622711005Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 278, - "CreatedAt": "2020-09-07T15:38:56.610644498Z", - "UpdatedAt": "2020-09-07T15:38:56.610644498Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 243, - "CreatedAt": "2020-09-07T15:26:07.494160354Z", - "UpdatedAt": "2020-09-07T15:26:07.494160354Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 225, - "CreatedAt": "2020-09-07T15:26:07.480920492Z", - "UpdatedAt": "2020-09-07T15:26:07.480920492Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 190, - "CreatedAt": "2020-09-07T15:19:17.455725424Z", - "UpdatedAt": "2020-09-07T15:19:17.455725424Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 172, - "CreatedAt": "2020-09-07T15:19:17.443238266Z", - "UpdatedAt": "2020-09-07T15:19:17.443238266Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 137, - "CreatedAt": "2020-09-07T15:10:40.235762522Z", - "UpdatedAt": "2020-09-07T15:10:40.235762522Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 119, - "CreatedAt": "2020-09-07T15:10:40.22311063Z", - "UpdatedAt": "2020-09-07T15:10:40.22311063Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 84, - "CreatedAt": "2020-09-06T23:14:39.839842395Z", - "UpdatedAt": "2020-09-06T23:14:39.839842395Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 66, - "CreatedAt": "2020-09-06T23:14:39.829237678Z", - "UpdatedAt": "2020-09-06T23:14:39.829237678Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 31, - "CreatedAt": "2020-08-28T07:55:27.812094858Z", - "UpdatedAt": "2020-08-28T07:55:27.812094858Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 13, - "CreatedAt": "2020-08-28T07:55:27.794713765Z", - "UpdatedAt": "2020-08-28T07:55:27.794713765Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 403, - "CreatedAt": "2020-09-08T21:39:26.566869-07:00", - "UpdatedAt": "2020-09-08T21:39:26.566869-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32, - "status": "passed", - "history": [{ - "ID": 385, - "CreatedAt": "2020-09-08T21:39:26.556503-07:00", - "UpdatedAt": "2020-09-08T21:39:26.556503-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }, { - "ID": 350, - "CreatedAt": "2020-09-07T15:47:21.320921272Z", - "UpdatedAt": "2020-09-07T15:47:21.320921272Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }, { - "ID": 332, - "CreatedAt": "2020-09-07T15:47:21.308359744Z", - "UpdatedAt": "2020-09-07T15:47:21.308359744Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }, { - "ID": 297, - "CreatedAt": "2020-09-07T15:38:56.622787005Z", - "UpdatedAt": "2020-09-07T15:38:56.622787005Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }, { - "ID": 279, - "CreatedAt": "2020-09-07T15:38:56.610731899Z", - "UpdatedAt": "2020-09-07T15:38:56.610731899Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }, { - "ID": 244, - "CreatedAt": "2020-09-07T15:26:07.494245356Z", - "UpdatedAt": "2020-09-07T15:26:07.494245356Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }, { - "ID": 226, - "CreatedAt": "2020-09-07T15:26:07.481005295Z", - "UpdatedAt": "2020-09-07T15:26:07.481005295Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }, { - "ID": 191, - "CreatedAt": "2020-09-07T15:19:17.455795324Z", - "UpdatedAt": "2020-09-07T15:19:17.455795324Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }, { - "ID": 173, - "CreatedAt": "2020-09-07T15:19:17.443317065Z", - "UpdatedAt": "2020-09-07T15:19:17.443317065Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }, { - "ID": 138, - "CreatedAt": "2020-09-07T15:10:40.235933223Z", - "UpdatedAt": "2020-09-07T15:10:40.235933223Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }, { - "ID": 120, - "CreatedAt": "2020-09-07T15:10:40.223208631Z", - "UpdatedAt": "2020-09-07T15:10:40.223208631Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }, { - "ID": 85, - "CreatedAt": "2020-09-06T23:14:39.839917897Z", - "UpdatedAt": "2020-09-06T23:14:39.839917897Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }, { - "ID": 67, - "CreatedAt": "2020-09-06T23:14:39.82930548Z", - "UpdatedAt": "2020-09-06T23:14:39.82930548Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }, { - "ID": 32, - "CreatedAt": "2020-08-28T07:55:27.812170947Z", - "UpdatedAt": "2020-08-28T07:55:27.812170947Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }, { - "ID": 14, - "CreatedAt": "2020-08-28T07:55:27.794809537Z", - "UpdatedAt": "2020-08-28T07:55:27.794809537Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "worst": 51, - "thresh": 0, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 32 - }] - }, { - "ID": 404, - "CreatedAt": "2020-09-08T21:39:26.566946-07:00", - "UpdatedAt": "2020-09-08T21:39:26.566946-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.007389855800729792, - "history": [{ - "ID": 386, - "CreatedAt": "2020-09-08T21:39:26.556577-07:00", - "UpdatedAt": "2020-09-08T21:39:26.556577-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 351, - "CreatedAt": "2020-09-07T15:47:21.320997672Z", - "UpdatedAt": "2020-09-07T15:47:21.320997672Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 333, - "CreatedAt": "2020-09-07T15:47:21.308448945Z", - "UpdatedAt": "2020-09-07T15:47:21.308448945Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 298, - "CreatedAt": "2020-09-07T15:38:56.622861506Z", - "UpdatedAt": "2020-09-07T15:38:56.622861506Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 280, - "CreatedAt": "2020-09-07T15:38:56.6108076Z", - "UpdatedAt": "2020-09-07T15:38:56.6108076Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 245, - "CreatedAt": "2020-09-07T15:26:07.494329358Z", - "UpdatedAt": "2020-09-07T15:26:07.494329358Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 227, - "CreatedAt": "2020-09-07T15:26:07.481094797Z", - "UpdatedAt": "2020-09-07T15:26:07.481094797Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 192, - "CreatedAt": "2020-09-07T15:19:17.455872523Z", - "UpdatedAt": "2020-09-07T15:19:17.455872523Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 174, - "CreatedAt": "2020-09-07T15:19:17.443397465Z", - "UpdatedAt": "2020-09-07T15:19:17.443397465Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 139, - "CreatedAt": "2020-09-07T15:10:40.236025724Z", - "UpdatedAt": "2020-09-07T15:10:40.236025724Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 121, - "CreatedAt": "2020-09-07T15:10:40.223270031Z", - "UpdatedAt": "2020-09-07T15:10:40.223270031Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 86, - "CreatedAt": "2020-09-06T23:14:39.8399883Z", - "UpdatedAt": "2020-09-06T23:14:39.8399883Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 68, - "CreatedAt": "2020-09-06T23:14:39.829370082Z", - "UpdatedAt": "2020-09-06T23:14:39.829370082Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 33, - "CreatedAt": "2020-08-28T07:55:27.812246492Z", - "UpdatedAt": "2020-08-28T07:55:27.812246492Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 196, - "name": "Reallocation Event Count", + "name": "Read Error Rate", "value": 100, + "thresh": 1, "worst": 100, - "thresh": 0, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 15, - "CreatedAt": "2020-08-28T07:55:27.794890531Z", - "UpdatedAt": "2020-08-28T07:55:27.794890531Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 196, - "name": "Reallocation Event Count", + }, + "10": { + "attribute_id": 10, + "name": "Spin Retry Count", "value": 100, + "thresh": 1, "worst": 100, - "thresh": 0, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }] - }, { - "ID": 405, - "CreatedAt": "2020-09-08T21:39:26.567013-07:00", - "UpdatedAt": "2020-09-08T21:39:26.567013-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 197, - "name": "Current Pending Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.025540791394761345, - "history": [{ - "ID": 387, - "CreatedAt": "2020-09-08T21:39:26.55665-07:00", - "UpdatedAt": "2020-09-08T21:39:26.55665-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 197, - "name": "Current Pending Sector Count", + }, + "12": { + "attribute_id": 12, + "name": "Power Cycle Count", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 100, + "raw_value": 9, + "raw_string": "9", "when_failed": "", "transformed_value": 0 - }, { - "ID": 352, - "CreatedAt": "2020-09-07T15:47:21.321080072Z", - "UpdatedAt": "2020-09-07T15:47:21.321080072Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 197, - "name": "Current Pending Sector Count", + }, + "192": { + "attribute_id": 192, + "name": "Power-off Retract Count", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 100, + "raw_value": 329, + "raw_string": "329", "when_failed": "", "transformed_value": 0 - }, { - "ID": 334, - "CreatedAt": "2020-09-07T15:47:21.308534945Z", - "UpdatedAt": "2020-09-07T15:47:21.308534945Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 197, - "name": "Current Pending Sector Count", + }, + "193": { + "attribute_id": 193, + "name": "Load Cycle Count", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 100, + "raw_value": 329, + "raw_string": "329", "when_failed": "", "transformed_value": 0 - }, { - "ID": 299, - "CreatedAt": "2020-09-07T15:38:56.622933307Z", - "UpdatedAt": "2020-09-07T15:38:56.622933307Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 197, - "name": "Current Pending Sector Count", - "value": 100, - "worst": 100, + }, + "194": { + "attribute_id": 194, + "name": "Temperature", + "value": 51, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 51, + "raw_value": 163210330144, + "raw_string": "32 (Min/Max 24/38)", "when_failed": "", "transformed_value": 0 - }, { - "ID": 281, - "CreatedAt": "2020-09-07T15:38:56.6108811Z", - "UpdatedAt": "2020-09-07T15:38:56.6108811Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 197, - "name": "Current Pending Sector Count", + }, + "196": { + "attribute_id": 196, + "name": "Reallocation Event Count", "value": 100, - "worst": 100, "thresh": 0, + "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 246, - "CreatedAt": "2020-09-07T15:26:07.494412661Z", - "UpdatedAt": "2020-09-07T15:26:07.494412661Z", - "DeletedAt": null, - "smart_id": 26, + }, + "197": { "attribute_id": 197, "name": "Current Pending Sector Count", "value": 100, - "worst": 100, "thresh": 0, + "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 228, - "CreatedAt": "2020-09-07T15:26:07.481180499Z", - "UpdatedAt": "2020-09-07T15:26:07.481180499Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 197, - "name": "Current Pending Sector Count", + }, + "198": { + "attribute_id": 198, + "name": "(Offline) Uncorrectable Sector Count", "value": 100, - "worst": 100, "thresh": 0, + "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 193, - "CreatedAt": "2020-09-07T15:19:17.455947323Z", - "UpdatedAt": "2020-09-07T15:19:17.455947323Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 197, - "name": "Current Pending Sector Count", + }, + "199": { + "attribute_id": 199, + "name": "UltraDMA CRC Error Count", "value": 100, - "worst": 100, "thresh": 0, + "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 175, - "CreatedAt": "2020-09-07T15:19:17.443471765Z", - "UpdatedAt": "2020-09-07T15:19:17.443471765Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 197, - "name": "Current Pending Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", + }, + "2": { + "attribute_id": 2, + "name": "Throughput Performance", + "value": 135, + "thresh": 54, + "worst": 135, + "raw_value": 108, + "raw_string": "108", "when_failed": "", "transformed_value": 0 - }, { - "ID": 140, - "CreatedAt": "2020-09-07T15:10:40.236107525Z", - "UpdatedAt": "2020-09-07T15:10:40.236107525Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 197, - "name": "Current Pending Sector Count", + }, + "22": { + "attribute_id": 22, + "name": "Current Helium Level", "value": 100, + "thresh": 25, "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "raw_value": 100, + "raw_string": "100", "when_failed": "", "transformed_value": 0 - }, { - "ID": 122, - "CreatedAt": "2020-09-07T15:10:40.223335031Z", - "UpdatedAt": "2020-09-07T15:10:40.223335031Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 197, - "name": "Current Pending Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", + }, + "3": { + "attribute_id": 3, + "name": "Spin-Up Time", + "value": 81, + "thresh": 1, + "worst": 81, + "raw_value": 30089675132, + "raw_string": "380 (Average 380)", "when_failed": "", "transformed_value": 0 - }, { - "ID": 87, - "CreatedAt": "2020-09-06T23:14:39.840059202Z", - "UpdatedAt": "2020-09-06T23:14:39.840059202Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 197, - "name": "Current Pending Sector Count", + }, + "4": { + "attribute_id": 4, + "name": "Start/Stop Count", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 100, + "raw_value": 9, + "raw_string": "9", "when_failed": "", "transformed_value": 0 - }, { - "ID": 69, - "CreatedAt": "2020-09-06T23:14:39.829440284Z", - "UpdatedAt": "2020-09-06T23:14:39.829440284Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 197, - "name": "Current Pending Sector Count", + }, + "5": { + "attribute_id": 5, + "name": "Reallocated Sectors Count", "value": 100, + "thresh": 1, "worst": 100, - "thresh": 0, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 34, - "CreatedAt": "2020-08-28T07:55:27.812321365Z", - "UpdatedAt": "2020-08-28T07:55:27.812321365Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 197, - "name": "Current Pending Sector Count", + }, + "7": { + "attribute_id": 7, + "name": "Seek Error Rate", "value": 100, + "thresh": 1, "worst": 100, - "thresh": 0, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 16, - "CreatedAt": "2020-08-28T07:55:27.794983884Z", - "UpdatedAt": "2020-08-28T07:55:27.794983884Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 197, - "name": "Current Pending Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", + }, + "8": { + "attribute_id": 8, + "name": "Seek Time Performance", + "value": 133, + "thresh": 20, + "worst": 133, + "raw_value": 18, + "raw_string": "18", "when_failed": "", "transformed_value": 0 - }] - }, { - "ID": 406, - "CreatedAt": "2020-09-08T21:39:26.567084-07:00", - "UpdatedAt": "2020-09-08T21:39:26.567084-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.028675322159886437, - "history": [{ - "ID": 388, - "CreatedAt": "2020-09-08T21:39:26.556721-07:00", - "UpdatedAt": "2020-09-08T21:39:26.556721-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", + }, + "9": { + "attribute_id": 9, + "name": "Power-On Hours", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 100, + "raw_value": 1730, + "raw_string": "1730", "when_failed": "", "transformed_value": 0 - }, { - "ID": 353, - "CreatedAt": "2020-09-07T15:47:21.321156173Z", - "UpdatedAt": "2020-09-07T15:47:21.321156173Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", + } + } + }, { + "date": "2021-01-23T16:24:06Z", + "device_wwn": "0x5000cca264eb01d7", + "device_protocol": "ATA", + "temp": 32, + "power_on_hours": 1730, + "power_cycle_count": 9, + "attrs": { + "1": { + "attribute_id": 1, + "name": "Read Error Rate", "value": 100, + "thresh": 1, "worst": 100, - "thresh": 0, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 335, - "CreatedAt": "2020-09-07T15:47:21.308621645Z", - "UpdatedAt": "2020-09-07T15:47:21.308621645Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", + }, + "10": { + "attribute_id": 10, + "name": "Spin Retry Count", "value": 100, + "thresh": 1, "worst": 100, - "thresh": 0, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 300, - "CreatedAt": "2020-09-07T15:38:56.623001907Z", - "UpdatedAt": "2020-09-07T15:38:56.623001907Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", + }, + "12": { + "attribute_id": 12, + "name": "Power Cycle Count", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 100, + "raw_value": 9, + "raw_string": "9", "when_failed": "", "transformed_value": 0 - }, { - "ID": 282, - "CreatedAt": "2020-09-07T15:38:56.610954501Z", - "UpdatedAt": "2020-09-07T15:38:56.610954501Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", + }, + "192": { + "attribute_id": 192, + "name": "Power-off Retract Count", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 100, + "raw_value": 329, + "raw_string": "329", "when_failed": "", "transformed_value": 0 - }, { - "ID": 247, - "CreatedAt": "2020-09-07T15:26:07.494502663Z", - "UpdatedAt": "2020-09-07T15:26:07.494502663Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", + }, + "193": { + "attribute_id": 193, + "name": "Load Cycle Count", "value": 100, + "thresh": 0, "worst": 100, + "raw_value": 329, + "raw_string": "329", + "when_failed": "", + "transformed_value": 0 + }, + "194": { + "attribute_id": 194, + "name": "Temperature", + "value": 51, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 51, + "raw_value": 163210330144, + "raw_string": "32 (Min/Max 24/38)", "when_failed": "", "transformed_value": 0 - }, { - "ID": 229, - "CreatedAt": "2020-09-07T15:26:07.481263302Z", - "UpdatedAt": "2020-09-07T15:26:07.481263302Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", + }, + "196": { + "attribute_id": 196, + "name": "Reallocation Event Count", "value": 100, - "worst": 100, "thresh": 0, + "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 194, - "CreatedAt": "2020-09-07T15:19:17.456016623Z", - "UpdatedAt": "2020-09-07T15:19:17.456016623Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", + }, + "197": { + "attribute_id": 197, + "name": "Current Pending Sector Count", "value": 100, - "worst": 100, "thresh": 0, + "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 176, - "CreatedAt": "2020-09-07T15:19:17.443544465Z", - "UpdatedAt": "2020-09-07T15:19:17.443544465Z", - "DeletedAt": null, - "smart_id": 19, + }, + "198": { "attribute_id": 198, "name": "(Offline) Uncorrectable Sector Count", "value": 100, - "worst": 100, "thresh": 0, + "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 141, - "CreatedAt": "2020-09-07T15:10:40.236230025Z", - "UpdatedAt": "2020-09-07T15:10:40.236230025Z", - "DeletedAt": null, - "smart_id": 14, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", + }, + "199": { + "attribute_id": 199, + "name": "UltraDMA CRC Error Count", "value": 100, - "worst": 100, "thresh": 0, + "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 123, - "CreatedAt": "2020-09-07T15:10:40.223397332Z", - "UpdatedAt": "2020-09-07T15:10:40.223397332Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", + }, + "2": { + "attribute_id": 2, + "name": "Throughput Performance", + "value": 135, + "thresh": 54, + "worst": 135, + "raw_value": 108, + "raw_string": "108", + "when_failed": "", + "transformed_value": 0 + }, + "22": { + "attribute_id": 22, + "name": "Current Helium Level", "value": 100, + "thresh": 25, "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "raw_value": 100, + "raw_string": "100", + "when_failed": "", + "transformed_value": 0 + }, + "3": { + "attribute_id": 3, + "name": "Spin-Up Time", + "value": 81, + "thresh": 1, + "worst": 81, + "raw_value": 30089675132, + "raw_string": "380 (Average 380)", "when_failed": "", "transformed_value": 0 - }, { - "ID": 88, - "CreatedAt": "2020-09-06T23:14:39.840162905Z", - "UpdatedAt": "2020-09-06T23:14:39.840162905Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", + }, + "4": { + "attribute_id": 4, + "name": "Start/Stop Count", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 100, + "raw_value": 9, + "raw_string": "9", "when_failed": "", "transformed_value": 0 - }, { - "ID": 70, - "CreatedAt": "2020-09-06T23:14:39.829535987Z", - "UpdatedAt": "2020-09-06T23:14:39.829535987Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", + }, + "5": { + "attribute_id": 5, + "name": "Reallocated Sectors Count", "value": 100, + "thresh": 1, "worst": 100, - "thresh": 0, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 35, - "CreatedAt": "2020-08-28T07:55:27.812396538Z", - "UpdatedAt": "2020-08-28T07:55:27.812396538Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", + }, + "7": { + "attribute_id": 7, + "name": "Seek Error Rate", "value": 100, + "thresh": 1, "worst": 100, - "thresh": 0, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 17, - "CreatedAt": "2020-08-28T07:55:27.795066287Z", - "UpdatedAt": "2020-08-28T07:55:27.795066287Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", + }, + "8": { + "attribute_id": 8, + "name": "Seek Time Performance", + "value": 133, + "thresh": 20, + "worst": 133, + "raw_value": 18, + "raw_string": "18", "when_failed": "", "transformed_value": 0 - }] - }, { - "ID": 407, - "CreatedAt": "2020-09-08T21:39:26.567154-07:00", - "UpdatedAt": "2020-09-08T21:39:26.567154-07:00", - "DeletedAt": null, - "smart_id": 44, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 389, - "CreatedAt": "2020-09-08T21:39:26.556788-07:00", - "UpdatedAt": "2020-09-08T21:39:26.556788-07:00", - "DeletedAt": null, - "smart_id": 43, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", + }, + "9": { + "attribute_id": 9, + "name": "Power-On Hours", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 100, + "raw_value": 1730, + "raw_string": "1730", "when_failed": "", "transformed_value": 0 - }, { - "ID": 354, - "CreatedAt": "2020-09-07T15:47:21.321272273Z", - "UpdatedAt": "2020-09-07T15:47:21.321272273Z", - "DeletedAt": null, - "smart_id": 38, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", + } + } + }, { + "date": "2021-01-23T16:25:46Z", + "device_wwn": "0x5000cca264eb01d7", + "device_protocol": "ATA", + "temp": 32, + "power_on_hours": 1730, + "power_cycle_count": 9, + "attrs": { + "1": { + "attribute_id": 1, + "name": "Read Error Rate", "value": 100, + "thresh": 1, "worst": 100, - "thresh": 0, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 336, - "CreatedAt": "2020-09-07T15:47:21.308717545Z", - "UpdatedAt": "2020-09-07T15:47:21.308717545Z", - "DeletedAt": null, - "smart_id": 37, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", + }, + "10": { + "attribute_id": 10, + "name": "Spin Retry Count", "value": 100, + "thresh": 1, "worst": 100, - "thresh": 0, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 301, - "CreatedAt": "2020-09-07T15:38:56.623082408Z", - "UpdatedAt": "2020-09-07T15:38:56.623082408Z", - "DeletedAt": null, - "smart_id": 32, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", + }, + "12": { + "attribute_id": 12, + "name": "Power Cycle Count", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 100, + "raw_value": 9, + "raw_string": "9", "when_failed": "", "transformed_value": 0 - }, { - "ID": 283, - "CreatedAt": "2020-09-07T15:38:56.611027902Z", - "UpdatedAt": "2020-09-07T15:38:56.611027902Z", - "DeletedAt": null, - "smart_id": 31, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", + }, + "192": { + "attribute_id": 192, + "name": "Power-off Retract Count", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 100, + "raw_value": 329, + "raw_string": "329", "when_failed": "", "transformed_value": 0 - }, { - "ID": 248, - "CreatedAt": "2020-09-07T15:26:07.494585565Z", - "UpdatedAt": "2020-09-07T15:26:07.494585565Z", - "DeletedAt": null, - "smart_id": 26, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", + }, + "193": { + "attribute_id": 193, + "name": "Load Cycle Count", "value": 100, + "thresh": 0, "worst": 100, + "raw_value": 329, + "raw_string": "329", + "when_failed": "", + "transformed_value": 0 + }, + "194": { + "attribute_id": 194, + "name": "Temperature", + "value": 51, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 51, + "raw_value": 163210330144, + "raw_string": "32 (Min/Max 24/38)", "when_failed": "", "transformed_value": 0 - }, { - "ID": 230, - "CreatedAt": "2020-09-07T15:26:07.481350204Z", - "UpdatedAt": "2020-09-07T15:26:07.481350204Z", - "DeletedAt": null, - "smart_id": 25, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", + }, + "196": { + "attribute_id": 196, + "name": "Reallocation Event Count", "value": 100, - "worst": 100, "thresh": 0, + "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 195, - "CreatedAt": "2020-09-07T15:19:17.456093323Z", - "UpdatedAt": "2020-09-07T15:19:17.456093323Z", - "DeletedAt": null, - "smart_id": 20, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", + }, + "197": { + "attribute_id": 197, + "name": "Current Pending Sector Count", "value": 100, - "worst": 100, "thresh": 0, + "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 177, - "CreatedAt": "2020-09-07T15:19:17.443622964Z", - "UpdatedAt": "2020-09-07T15:19:17.443622964Z", - "DeletedAt": null, - "smart_id": 19, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", + }, + "198": { + "attribute_id": 198, + "name": "(Offline) Uncorrectable Sector Count", "value": 100, - "worst": 100, "thresh": 0, + "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 142, - "CreatedAt": "2020-09-07T15:10:40.236299626Z", - "UpdatedAt": "2020-09-07T15:10:40.236299626Z", - "DeletedAt": null, - "smart_id": 14, + }, + "199": { "attribute_id": 199, "name": "UltraDMA CRC Error Count", "value": 100, - "worst": 100, "thresh": 0, + "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 124, - "CreatedAt": "2020-09-07T15:10:40.223460532Z", - "UpdatedAt": "2020-09-07T15:10:40.223460532Z", - "DeletedAt": null, - "smart_id": 13, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", + }, + "2": { + "attribute_id": 2, + "name": "Throughput Performance", + "value": 135, + "thresh": 54, + "worst": 135, + "raw_value": 108, + "raw_string": "108", + "when_failed": "", + "transformed_value": 0 + }, + "22": { + "attribute_id": 22, + "name": "Current Helium Level", "value": 100, + "thresh": 25, "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "raw_value": 100, + "raw_string": "100", "when_failed": "", "transformed_value": 0 - }, { - "ID": 89, - "CreatedAt": "2020-09-06T23:14:39.840242107Z", - "UpdatedAt": "2020-09-06T23:14:39.840242107Z", - "DeletedAt": null, - "smart_id": 8, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", + }, + "3": { + "attribute_id": 3, + "name": "Spin-Up Time", + "value": 81, + "thresh": 1, + "worst": 81, + "raw_value": 30089675132, + "raw_string": "380 (Average 380)", + "when_failed": "", + "transformed_value": 0 + }, + "4": { + "attribute_id": 4, + "name": "Start/Stop Count", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 100, + "raw_value": 9, + "raw_string": "9", "when_failed": "", "transformed_value": 0 - }, { - "ID": 71, - "CreatedAt": "2020-09-06T23:14:39.82963599Z", - "UpdatedAt": "2020-09-06T23:14:39.82963599Z", - "DeletedAt": null, - "smart_id": 7, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", + }, + "5": { + "attribute_id": 5, + "name": "Reallocated Sectors Count", "value": 100, + "thresh": 1, "worst": 100, - "thresh": 0, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 36, - "CreatedAt": "2020-08-28T07:55:27.812495499Z", - "UpdatedAt": "2020-08-28T07:55:27.812495499Z", - "DeletedAt": null, - "smart_id": 2, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", + }, + "7": { + "attribute_id": 7, + "name": "Seek Error Rate", "value": 100, + "thresh": 1, "worst": 100, - "thresh": 0, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 18, - "CreatedAt": "2020-08-28T07:55:27.795190163Z", - "UpdatedAt": "2020-08-28T07:55:27.795190163Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", + }, + "8": { + "attribute_id": 8, + "name": "Seek Time Performance", + "value": 133, + "thresh": 20, + "worst": 133, + "raw_value": 18, + "raw_string": "18", + "when_failed": "", + "transformed_value": 0 + }, + "9": { + "attribute_id": 9, + "name": "Power-On Hours", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 100, + "raw_value": 1730, + "raw_string": "1730", "when_failed": "", "transformed_value": 0 - }] - }], - "nvme_attributes": [], - "scsi_attributes": [] + } + } }] - }, "metadata": { + }, + "metadata": { "1": { "ideal": "low", "critical": false, @@ -4420,12 +665,22 @@ export const sdb = { "high": 125, "annual_failure_rate": 0.06390002135229157, "error_interval": [0.05852004676110847, 0.06964160930553712] - }, {"low": 125, "high": 140, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 125, + "high": 140, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 140, "high": 155, "annual_failure_rate": 0, "error_interval": [0, 0] - }, {"low": 155, "high": 170, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 155, + "high": 170, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 170, "high": 185, "annual_failure_rate": 0, @@ -4469,17 +724,32 @@ export const sdb = { "high": 80, "annual_failure_rate": 0.5555555555555556, "error_interval": [0.014065448880161053, 3.095357439410498] - }, {"low": 80, "high": 160, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 80, + "high": 160, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 160, "high": 240, "annual_failure_rate": 0, "error_interval": [0, 0] - }, {"low": 240, "high": 320, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 240, + "high": 320, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 320, "high": 400, "annual_failure_rate": 0, "error_interval": [0, 0] - }, {"low": 400, "high": 480, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 400, + "high": 480, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 480, "high": 560, "annual_failure_rate": 0, @@ -4535,7 +805,12 @@ export const sdb = { "description": "Uncorrected read errors reported to the operating system.", "display_type": "normalized" }, - "170": {"ideal": "", "critical": false, "description": "See attribute E8.", "display_type": "normalized"}, + "170": { + "ideal": "", + "critical": false, + "description": "See attribute E8.", + "display_type": "normalized" + }, "171": { "ideal": "", "critical": false, @@ -4646,7 +921,12 @@ export const sdb = { "high": 130, "annual_failure_rate": 0.40299684542586756, "error_interval": [0.16202563309223209, 0.8303275247667772] - }, {"low": 130, "high": 260, "annual_failure_rate": 0, "error_interval": [0, 0]}], + }, { + "low": 130, + "high": 260, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }], "display_type": "raw" }, "184": { @@ -4658,12 +938,22 @@ export const sdb = { "high": 94, "annual_failure_rate": 1.631212012870933, "error_interval": [1.055634407303844, 2.407990716767714] - }, {"low": 94, "high": 95, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 94, + "high": 95, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 95, "high": 96, "annual_failure_rate": 0, "error_interval": [0, 0] - }, {"low": 96, "high": 97, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 96, + "high": 97, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 97, "high": 97, "annual_failure_rate": 0, @@ -4945,12 +1235,22 @@ export const sdb = { "high": 60, "annual_failure_rate": 0.05672658497265746, "error_interval": [0.043182904776447234, 0.07317316161437043] - }, {"low": 60, "high": 72, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 60, + "high": 72, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 72, "high": 84, "annual_failure_rate": 0, "error_interval": [0, 0] - }, {"low": 84, "high": 96, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 84, + "high": 96, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 96, "high": 108, "annual_failure_rate": 0.04074570216566197, @@ -5492,7 +1792,12 @@ export const sdb = { "high": 91, "annual_failure_rate": 0.12262136155304391, "error_interval": [0.0670382394080032, 0.20573780888032978] - }, {"low": 91, "high": 104, "annual_failure_rate": 0, "error_interval": [0, 0]}], + }, { + "low": 91, + "high": 104, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }], "display_type": "raw" }, "5": { @@ -5572,12 +1877,22 @@ export const sdb = { "high": 112, "annual_failure_rate": 0.01087335627722523, "error_interval": [0.008732197944943352, 0.013380600544561905] - }, {"low": 112, "high": 130, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 112, + "high": 130, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 130, "high": 148, "annual_failure_rate": 0, "error_interval": [0, 0] - }, {"low": 148, "high": 166, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 148, + "high": 166, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 166, "high": 184, "annual_failure_rate": 0, @@ -5602,5 +1917,6 @@ export const sdb = { "description": "Count of hours in power-on state. The raw value of this attribute shows total count of hours (or minutes, or seconds, depending on manufacturer) in power-on state. By default, the total expected lifetime of a hard disk in perfect condition is defined as 5 years (running every day and night on all days). This is equal to 1825 days in 24/7 mode or 43800 hours. On some pre-2005 drives, this raw value may advance erratically and/or \"wrap around\" (reset to zero periodically).", "display_type": "normalized" } - }, "success": true + }, + "success": true } diff --git a/webapp/frontend/src/app/data/mock/device/details/sdc.ts b/webapp/frontend/src/app/data/mock/device/details/sdc.ts index 5d6935e..4bf402f 100644 --- a/webapp/frontend/src/app/data/mock/device/details/sdc.ts +++ b/webapp/frontend/src/app/data/mock/device/details/sdc.ts @@ -1,2127 +1,226 @@ export const sdc = { "data": { - "CreatedAt": "2020-08-28T07:55:27.75951336Z", - "UpdatedAt": "2020-09-08T21:39:26.568442-07:00", - "DeletedAt": null, - "wwn": "0x5000cca264ec3183", - "device_name": "sdc", - "manufacturer": "ATA", - "model_name": "WDC_WD140EDFZ-11A0VA0", - "interface_type": "SCSI", - "interface_speed": "1.5 Gb/s", - "host_id": "NAS", - "serial_number": "9RK4XXXXX", - "firmware": "MS1OA650", - "rotational_speed": 7200, - "capacity": 500107862016, - "form_factor": "3.5 inches", - "smart_support": false, - "device_protocol": "ATA", - "device_type": "usbjmicron", - "smart_results": [{ - "ID": 45, - "CreatedAt": "2020-09-08T21:39:26.569345-07:00", - "UpdatedAt": "2020-09-08T21:39:26.569345-07:00", + "device": { + "CreatedAt": "2021-06-24T21:17:31.303033-07:00", + "UpdatedAt": "2021-06-26T14:26:20.449968-07:00", "DeletedAt": null, + "wwn": "0x5000cca264ec3183", + "device_name": "sdc", + "manufacturer": "ATA", + "model_name": "WDC_WD140EDFZ-11A0VA0", + "interface_type": "SCSI", + "interface_speed": "", + "serial_number": "9RK4XXXXX", + "firmware": "MS1OA650", + "rotational_speed": 0, + "capacity": 14000519643136, + "form_factor": "", + "smart_support": false, + "device_protocol": "ATA", + "device_type": "", + "label": "", + "host_id": "", + "device_status": 1 + }, + "smart_results": [{ + "date": "2020-07-08T13:48:23Z", "device_wwn": "0x5000cca264ec3183", - "date": "2020-07-08T06:48:23-07:00", - "smart_status": "failed", + "device_protocol": "ATA", "temp": 25, "power_on_hours": 65592, "power_cycle_count": 86, - "ata_attributes": [{ - "ID": 408, - "CreatedAt": "2020-09-08T21:39:26.569651-07:00", - "UpdatedAt": "2020-09-08T21:39:26.569651-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 16, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.034155719633986996, - "history": [{ - "ID": 355, - "CreatedAt": "2020-09-07T15:47:21.331077494Z", - "UpdatedAt": "2020-09-07T15:47:21.331077494Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 16, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 302, - "CreatedAt": "2020-09-07T15:38:56.628275154Z", - "UpdatedAt": "2020-09-07T15:38:56.628275154Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 16, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 249, - "CreatedAt": "2020-09-07T15:26:07.499652704Z", - "UpdatedAt": "2020-09-07T15:26:07.499652704Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 16, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 196, - "CreatedAt": "2020-09-07T15:19:17.461974003Z", - "UpdatedAt": "2020-09-07T15:19:17.461974003Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 16, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 143, - "CreatedAt": "2020-09-07T15:10:40.241379163Z", - "UpdatedAt": "2020-09-07T15:10:40.241379163Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 16, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 90, - "CreatedAt": "2020-09-06T23:14:39.844234727Z", - "UpdatedAt": "2020-09-06T23:14:39.844234727Z", - "DeletedAt": null, - "smart_id": 9, + "attrs": { + "1": { "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 16, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 37, - "CreatedAt": "2020-08-28T07:55:27.822615291Z", - "UpdatedAt": "2020-08-28T07:55:27.822615291Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "worst": 100, - "thresh": 16, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 409, - "CreatedAt": "2020-09-08T21:39:26.569778-07:00", - "UpdatedAt": "2020-09-08T21:39:26.569778-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 136, - "worst": 136, - "thresh": 54, - "raw_value": 91, - "raw_string": "91", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 356, - "CreatedAt": "2020-09-07T15:47:21.331211195Z", - "UpdatedAt": "2020-09-07T15:47:21.331211195Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 136, - "worst": 136, - "thresh": 54, - "raw_value": 91, - "raw_string": "91", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 303, - "CreatedAt": "2020-09-07T15:38:56.628397755Z", - "UpdatedAt": "2020-09-07T15:38:56.628397755Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 136, - "worst": 136, - "thresh": 54, - "raw_value": 91, - "raw_string": "91", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 250, - "CreatedAt": "2020-09-07T15:26:07.499816008Z", - "UpdatedAt": "2020-09-07T15:26:07.499816008Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 136, - "worst": 136, - "thresh": 54, - "raw_value": 91, - "raw_string": "91", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 197, - "CreatedAt": "2020-09-07T15:19:17.462101002Z", - "UpdatedAt": "2020-09-07T15:19:17.462101002Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 136, - "worst": 136, - "thresh": 54, - "raw_value": 91, - "raw_string": "91", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 144, - "CreatedAt": "2020-09-07T15:10:40.241492664Z", - "UpdatedAt": "2020-09-07T15:10:40.241492664Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 136, - "worst": 136, - "thresh": 54, - "raw_value": 91, - "raw_string": "91", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 91, - "CreatedAt": "2020-09-06T23:14:39.84435983Z", - "UpdatedAt": "2020-09-06T23:14:39.84435983Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 136, - "worst": 136, - "thresh": 54, - "raw_value": 91, - "raw_string": "91", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 38, - "CreatedAt": "2020-08-28T07:55:27.822739564Z", - "UpdatedAt": "2020-08-28T07:55:27.822739564Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 2, - "name": "Throughput Performance", - "value": 136, - "worst": 136, - "thresh": 54, - "raw_value": 91, - "raw_string": "91", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 410, - "CreatedAt": "2020-09-08T21:39:26.569881-07:00", - "UpdatedAt": "2020-09-08T21:39:26.569881-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 125, - "worst": 125, - "thresh": 24, - "raw_value": 17192124596, - "raw_string": "180 (Average 187)", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.009100406705780476, - "history": [{ - "ID": 357, - "CreatedAt": "2020-09-07T15:47:21.331308395Z", - "UpdatedAt": "2020-09-07T15:47:21.331308395Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 125, - "worst": 125, - "thresh": 24, - "raw_value": 17192124596, - "raw_string": "180 (Average 187)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 304, - "CreatedAt": "2020-09-07T15:38:56.628487555Z", - "UpdatedAt": "2020-09-07T15:38:56.628487555Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 125, - "worst": 125, - "thresh": 24, - "raw_value": 17192124596, - "raw_string": "180 (Average 187)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 251, - "CreatedAt": "2020-09-07T15:26:07.499919611Z", - "UpdatedAt": "2020-09-07T15:26:07.499919611Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 125, - "worst": 125, - "thresh": 24, - "raw_value": 17192124596, - "raw_string": "180 (Average 187)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 198, - "CreatedAt": "2020-09-07T15:19:17.462188402Z", - "UpdatedAt": "2020-09-07T15:19:17.462188402Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 125, - "worst": 125, - "thresh": 24, - "raw_value": 17192124596, - "raw_string": "180 (Average 187)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 145, - "CreatedAt": "2020-09-07T15:10:40.241569664Z", - "UpdatedAt": "2020-09-07T15:10:40.241569664Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 125, - "worst": 125, - "thresh": 24, - "raw_value": 17192124596, - "raw_string": "180 (Average 187)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 92, - "CreatedAt": "2020-09-06T23:14:39.844441733Z", - "UpdatedAt": "2020-09-06T23:14:39.844441733Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 125, - "worst": 125, - "thresh": 24, - "raw_value": 17192124596, - "raw_string": "180 (Average 187)", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 39, - "CreatedAt": "2020-08-28T07:55:27.822829942Z", - "UpdatedAt": "2020-08-28T07:55:27.822829942Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 125, - "worst": 125, - "thresh": 24, - "raw_value": 17192124596, - "raw_string": "180 (Average 187)", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 411, - "CreatedAt": "2020-09-08T21:39:26.569964-07:00", - "UpdatedAt": "2020-09-08T21:39:26.569964-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0, - "status": "warn", - "status_reason": "Observed Failure Rate for Attribute is greater than 10%", - "failure_rate": 0.12262136155304391, - "history": [{ - "ID": 358, - "CreatedAt": "2020-09-07T15:47:21.331396495Z", - "UpdatedAt": "2020-09-07T15:47:21.331396495Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 305, - "CreatedAt": "2020-09-07T15:38:56.628567356Z", - "UpdatedAt": "2020-09-07T15:38:56.628567356Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 252, - "CreatedAt": "2020-09-07T15:26:07.500014814Z", - "UpdatedAt": "2020-09-07T15:26:07.500014814Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 199, - "CreatedAt": "2020-09-07T15:19:17.462366102Z", - "UpdatedAt": "2020-09-07T15:19:17.462366102Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 146, - "CreatedAt": "2020-09-07T15:10:40.241649265Z", - "UpdatedAt": "2020-09-07T15:10:40.241649265Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 93, - "CreatedAt": "2020-09-06T23:14:39.844534936Z", - "UpdatedAt": "2020-09-06T23:14:39.844534936Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 40, - "CreatedAt": "2020-08-28T07:55:27.822921756Z", - "UpdatedAt": "2020-08-28T07:55:27.822921756Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 412, - "CreatedAt": "2020-09-08T21:39:26.570087-07:00", - "UpdatedAt": "2020-09-08T21:39:26.570087-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 1, - "worst": 1, - "thresh": 5, - "raw_value": 1975, - "raw_string": "1975", - "when_failed": "now", - "transformed_value": 0, - "status": "failed", - "status_reason": "Observed Failure Rate for Critical Attribute is greater than 10%", - "failure_rate": 1.5028253400346423, - "history": [{ - "ID": 359, - "CreatedAt": "2020-09-07T15:47:21.331487495Z", - "UpdatedAt": "2020-09-07T15:47:21.331487495Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 1, - "worst": 1, - "thresh": 5, - "raw_value": 1975, - "raw_string": "1975", - "when_failed": "now", - "transformed_value": 0 - }, { - "ID": 306, - "CreatedAt": "2020-09-07T15:38:56.628646457Z", - "UpdatedAt": "2020-09-07T15:38:56.628646457Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 1, - "worst": 1, - "thresh": 5, - "raw_value": 1975, - "raw_string": "1975", - "when_failed": "now", - "transformed_value": 0 - }, { - "ID": 253, - "CreatedAt": "2020-09-07T15:26:07.500102516Z", - "UpdatedAt": "2020-09-07T15:26:07.500102516Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 1, - "worst": 1, - "thresh": 5, - "raw_value": 1975, - "raw_string": "1975", - "when_failed": "now", - "transformed_value": 0 - }, { - "ID": 200, - "CreatedAt": "2020-09-07T15:19:17.462455401Z", - "UpdatedAt": "2020-09-07T15:19:17.462455401Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 1, - "worst": 1, - "thresh": 5, - "raw_value": 1975, - "raw_string": "1975", - "when_failed": "now", - "transformed_value": 0 - }, { - "ID": 147, - "CreatedAt": "2020-09-07T15:10:40.241718365Z", - "UpdatedAt": "2020-09-07T15:10:40.241718365Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 1, - "worst": 1, - "thresh": 5, - "raw_value": 1975, - "raw_string": "1975", - "when_failed": "now", - "transformed_value": 0 - }, { - "ID": 94, - "CreatedAt": "2020-09-06T23:14:39.844608938Z", - "UpdatedAt": "2020-09-06T23:14:39.844608938Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 1, - "worst": 1, - "thresh": 5, - "raw_value": 1975, - "raw_string": "1975", - "when_failed": "now", - "transformed_value": 0 - }, { - "ID": 41, - "CreatedAt": "2020-08-28T07:55:27.823009241Z", - "UpdatedAt": "2020-08-28T07:55:27.823009241Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 1, - "worst": 1, - "thresh": 5, - "raw_value": 1975, - "raw_string": "1975", - "when_failed": "now", - "transformed_value": 0 - }] - }, { - "ID": 413, - "CreatedAt": "2020-09-08T21:39:26.570167-07:00", - "UpdatedAt": "2020-09-08T21:39:26.570167-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 67, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.01087335627722523, - "history": [{ - "ID": 360, - "CreatedAt": "2020-09-07T15:47:21.331571895Z", - "UpdatedAt": "2020-09-07T15:47:21.331571895Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 67, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 307, - "CreatedAt": "2020-09-07T15:38:56.628722958Z", - "UpdatedAt": "2020-09-07T15:38:56.628722958Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 67, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 254, - "CreatedAt": "2020-09-07T15:26:07.500193018Z", - "UpdatedAt": "2020-09-07T15:26:07.500193018Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 67, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 201, - "CreatedAt": "2020-09-07T15:19:17.462534501Z", - "UpdatedAt": "2020-09-07T15:19:17.462534501Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 67, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 148, - "CreatedAt": "2020-09-07T15:10:40.241808366Z", - "UpdatedAt": "2020-09-07T15:10:40.241808366Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 67, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 95, - "CreatedAt": "2020-09-06T23:14:39.84467344Z", - "UpdatedAt": "2020-09-06T23:14:39.84467344Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 67, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 42, - "CreatedAt": "2020-08-28T07:55:27.823120387Z", - "UpdatedAt": "2020-08-28T07:55:27.823120387Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "worst": 100, - "thresh": 67, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 414, - "CreatedAt": "2020-09-08T21:39:26.57024-07:00", - "UpdatedAt": "2020-09-08T21:39:26.57024-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 118, - "worst": 118, - "thresh": 20, - "raw_value": 33, - "raw_string": "33", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 361, - "CreatedAt": "2020-09-07T15:47:21.331652696Z", - "UpdatedAt": "2020-09-07T15:47:21.331652696Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 118, - "worst": 118, - "thresh": 20, - "raw_value": 33, - "raw_string": "33", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 308, - "CreatedAt": "2020-09-07T15:38:56.628830258Z", - "UpdatedAt": "2020-09-07T15:38:56.628830258Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 118, - "worst": 118, - "thresh": 20, - "raw_value": 33, - "raw_string": "33", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 255, - "CreatedAt": "2020-09-07T15:26:07.500281521Z", - "UpdatedAt": "2020-09-07T15:26:07.500281521Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 118, - "worst": 118, - "thresh": 20, - "raw_value": 33, - "raw_string": "33", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 202, - "CreatedAt": "2020-09-07T15:19:17.462611201Z", - "UpdatedAt": "2020-09-07T15:19:17.462611201Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 118, - "worst": 118, - "thresh": 20, - "raw_value": 33, - "raw_string": "33", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 149, - "CreatedAt": "2020-09-07T15:10:40.241893167Z", - "UpdatedAt": "2020-09-07T15:10:40.241893167Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 118, - "worst": 118, - "thresh": 20, - "raw_value": 33, - "raw_string": "33", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 96, - "CreatedAt": "2020-09-06T23:14:39.844746142Z", - "UpdatedAt": "2020-09-06T23:14:39.844746142Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 118, - "worst": 118, - "thresh": 20, - "raw_value": 33, - "raw_string": "33", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 43, - "CreatedAt": "2020-08-28T07:55:27.823221736Z", - "UpdatedAt": "2020-08-28T07:55:27.823221736Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 118, - "worst": 118, - "thresh": 20, - "raw_value": 33, - "raw_string": "33", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 415, - "CreatedAt": "2020-09-08T21:39:26.570316-07:00", - "UpdatedAt": "2020-09-08T21:39:26.570316-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 91, - "worst": 91, - "thresh": 0, - "raw_value": 65592, - "raw_string": "65592", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 362, - "CreatedAt": "2020-09-07T15:47:21.331733496Z", - "UpdatedAt": "2020-09-07T15:47:21.331733496Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 91, - "worst": 91, - "thresh": 0, - "raw_value": 65592, - "raw_string": "65592", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 309, - "CreatedAt": "2020-09-07T15:38:56.628909459Z", - "UpdatedAt": "2020-09-07T15:38:56.628909459Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 91, - "worst": 91, - "thresh": 0, - "raw_value": 65592, - "raw_string": "65592", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 256, - "CreatedAt": "2020-09-07T15:26:07.500372023Z", - "UpdatedAt": "2020-09-07T15:26:07.500372023Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 91, - "worst": 91, - "thresh": 0, - "raw_value": 65592, - "raw_string": "65592", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 203, - "CreatedAt": "2020-09-07T15:19:17.4627161Z", - "UpdatedAt": "2020-09-07T15:19:17.4627161Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 91, - "worst": 91, - "thresh": 0, - "raw_value": 65592, - "raw_string": "65592", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 150, - "CreatedAt": "2020-09-07T15:10:40.241974767Z", - "UpdatedAt": "2020-09-07T15:10:40.241974767Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 91, - "worst": 91, - "thresh": 0, - "raw_value": 65592, - "raw_string": "65592", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 97, - "CreatedAt": "2020-09-06T23:14:39.844810044Z", - "UpdatedAt": "2020-09-06T23:14:39.844810044Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 91, - "worst": 91, - "thresh": 0, - "raw_value": 65592, - "raw_string": "65592", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 44, - "CreatedAt": "2020-08-28T07:55:27.823321577Z", - "UpdatedAt": "2020-08-28T07:55:27.823321577Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 91, - "worst": 91, - "thresh": 0, - "raw_value": 65592, - "raw_string": "65592", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 416, - "CreatedAt": "2020-09-08T21:39:26.570394-07:00", - "UpdatedAt": "2020-09-08T21:39:26.570394-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 60, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.05459827163896099, - "history": [{ - "ID": 363, - "CreatedAt": "2020-09-07T15:47:21.331813896Z", - "UpdatedAt": "2020-09-07T15:47:21.331813896Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 60, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 310, - "CreatedAt": "2020-09-07T15:38:56.62898266Z", - "UpdatedAt": "2020-09-07T15:38:56.62898266Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 60, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 257, - "CreatedAt": "2020-09-07T15:26:07.500462326Z", - "UpdatedAt": "2020-09-07T15:26:07.500462326Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 60, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 204, - "CreatedAt": "2020-09-07T15:19:17.462794Z", - "UpdatedAt": "2020-09-07T15:19:17.462794Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 60, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 151, - "CreatedAt": "2020-09-07T15:10:40.242057668Z", - "UpdatedAt": "2020-09-07T15:10:40.242057668Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 60, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 98, - "CreatedAt": "2020-09-06T23:14:39.844880446Z", - "UpdatedAt": "2020-09-06T23:14:39.844880446Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 60, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 45, - "CreatedAt": "2020-08-28T07:55:27.823417848Z", - "UpdatedAt": "2020-08-28T07:55:27.823417848Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 60, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 417, - "CreatedAt": "2020-09-08T21:39:26.570475-07:00", - "UpdatedAt": "2020-09-08T21:39:26.570475-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0, - "status": "warn", - "status_reason": "Observed Failure Rate for Attribute is greater than 10%", - "failure_rate": 0.12354840389522469, - "history": [{ - "ID": 364, - "CreatedAt": "2020-09-07T15:47:21.331899296Z", - "UpdatedAt": "2020-09-07T15:47:21.331899296Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 311, - "CreatedAt": "2020-09-07T15:38:56.629065161Z", - "UpdatedAt": "2020-09-07T15:38:56.629065161Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 258, - "CreatedAt": "2020-09-07T15:26:07.500549628Z", - "UpdatedAt": "2020-09-07T15:26:07.500549628Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 205, - "CreatedAt": "2020-09-07T15:19:17.4628661Z", - "UpdatedAt": "2020-09-07T15:19:17.4628661Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 152, - "CreatedAt": "2020-09-07T15:10:40.242167169Z", - "UpdatedAt": "2020-09-07T15:10:40.242167169Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 99, - "CreatedAt": "2020-09-06T23:14:39.844953848Z", - "UpdatedAt": "2020-09-06T23:14:39.844953848Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 46, - "CreatedAt": "2020-08-28T07:55:27.823514062Z", - "UpdatedAt": "2020-08-28T07:55:27.823514062Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 418, - "CreatedAt": "2020-09-08T21:39:26.570559-07:00", - "UpdatedAt": "2020-09-08T21:39:26.570559-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 365, - "CreatedAt": "2020-09-07T15:47:21.332006096Z", - "UpdatedAt": "2020-09-07T15:47:21.332006096Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 312, - "CreatedAt": "2020-09-07T15:38:56.629162161Z", - "UpdatedAt": "2020-09-07T15:38:56.629162161Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 259, - "CreatedAt": "2020-09-07T15:26:07.500657031Z", - "UpdatedAt": "2020-09-07T15:26:07.500657031Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 206, - "CreatedAt": "2020-09-07T15:19:17.462996099Z", - "UpdatedAt": "2020-09-07T15:19:17.462996099Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 153, - "CreatedAt": "2020-09-07T15:10:40.242253969Z", - "UpdatedAt": "2020-09-07T15:10:40.242253969Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 100, - "CreatedAt": "2020-09-06T23:14:39.84503215Z", - "UpdatedAt": "2020-09-06T23:14:39.84503215Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 47, - "CreatedAt": "2020-08-28T07:55:27.823595321Z", - "UpdatedAt": "2020-08-28T07:55:27.823595321Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 419, - "CreatedAt": "2020-09-08T21:39:26.57063-07:00", - "UpdatedAt": "2020-09-08T21:39:26.57063-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 366, - "CreatedAt": "2020-09-07T15:47:21.332093797Z", - "UpdatedAt": "2020-09-07T15:47:21.332093797Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 313, - "CreatedAt": "2020-09-07T15:38:56.629235062Z", - "UpdatedAt": "2020-09-07T15:38:56.629235062Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 260, - "CreatedAt": "2020-09-07T15:26:07.500743533Z", - "UpdatedAt": "2020-09-07T15:26:07.500743533Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 207, - "CreatedAt": "2020-09-07T15:19:17.463072899Z", - "UpdatedAt": "2020-09-07T15:19:17.463072899Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 154, - "CreatedAt": "2020-09-07T15:10:40.24235167Z", - "UpdatedAt": "2020-09-07T15:10:40.24235167Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 101, - "CreatedAt": "2020-09-06T23:14:39.845090052Z", - "UpdatedAt": "2020-09-06T23:14:39.845090052Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 48, - "CreatedAt": "2020-08-28T07:55:27.823681715Z", - "UpdatedAt": "2020-08-28T07:55:27.823681715Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 95, - "worst": 95, - "thresh": 0, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 420, - "CreatedAt": "2020-09-08T21:39:26.570714-07:00", - "UpdatedAt": "2020-09-08T21:39:26.570714-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 194, - "name": "Temperature", - "value": 240, - "worst": 240, - "thresh": 0, - "raw_value": 167504969753, - "raw_string": "25 (Min/Max 19/39)", - "when_failed": "", - "transformed_value": 25, - "status": "passed", - "history": [{ - "ID": 367, - "CreatedAt": "2020-09-07T15:47:21.332179497Z", - "UpdatedAt": "2020-09-07T15:47:21.332179497Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 194, - "name": "Temperature", - "value": 240, - "worst": 240, - "thresh": 0, - "raw_value": 167504969753, - "raw_string": "25 (Min/Max 19/39)", - "when_failed": "", - "transformed_value": 25 - }, { - "ID": 314, - "CreatedAt": "2020-09-07T15:38:56.629309963Z", - "UpdatedAt": "2020-09-07T15:38:56.629309963Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 194, - "name": "Temperature", - "value": 240, - "worst": 240, - "thresh": 0, - "raw_value": 167504969753, - "raw_string": "25 (Min/Max 19/39)", - "when_failed": "", - "transformed_value": 25 - }, { - "ID": 261, - "CreatedAt": "2020-09-07T15:26:07.500841536Z", - "UpdatedAt": "2020-09-07T15:26:07.500841536Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 194, - "name": "Temperature", - "value": 240, - "worst": 240, - "thresh": 0, - "raw_value": 167504969753, - "raw_string": "25 (Min/Max 19/39)", - "when_failed": "", - "transformed_value": 25 - }, { - "ID": 208, - "CreatedAt": "2020-09-07T15:19:17.463146099Z", - "UpdatedAt": "2020-09-07T15:19:17.463146099Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 194, - "name": "Temperature", - "value": 240, - "worst": 240, - "thresh": 0, - "raw_value": 167504969753, - "raw_string": "25 (Min/Max 19/39)", - "when_failed": "", - "transformed_value": 25 - }, { - "ID": 155, - "CreatedAt": "2020-09-07T15:10:40.242422871Z", - "UpdatedAt": "2020-09-07T15:10:40.242422871Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 194, - "name": "Temperature", - "value": 240, - "worst": 240, - "thresh": 0, - "raw_value": 167504969753, - "raw_string": "25 (Min/Max 19/39)", - "when_failed": "", - "transformed_value": 25 - }, { - "ID": 102, - "CreatedAt": "2020-09-06T23:14:39.845149154Z", - "UpdatedAt": "2020-09-06T23:14:39.845149154Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 194, - "name": "Temperature", - "value": 240, - "worst": 240, - "thresh": 0, - "raw_value": 167504969753, - "raw_string": "25 (Min/Max 19/39)", - "when_failed": "", - "transformed_value": 25 - }, { - "ID": 49, - "CreatedAt": "2020-08-28T07:55:27.823787578Z", - "UpdatedAt": "2020-08-28T07:55:27.823787578Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 194, - "name": "Temperature", - "value": 240, - "worst": 240, - "thresh": 0, - "raw_value": 167504969753, - "raw_string": "25 (Min/Max 19/39)", - "when_failed": "", - "transformed_value": 25 - }] - }, { - "ID": 421, - "CreatedAt": "2020-09-08T21:39:26.570794-07:00", - "UpdatedAt": "2020-09-08T21:39:26.570794-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 1, - "worst": 1, - "thresh": 0, - "raw_value": 3831, - "raw_string": "3831", - "when_failed": "", - "transformed_value": 0, - "status": "warn", - "status_reason": "Could not determine Observed Failure Rate for Critical Attribute", - "history": [{ - "ID": 368, - "CreatedAt": "2020-09-07T15:47:21.332261097Z", - "UpdatedAt": "2020-09-07T15:47:21.332261097Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 1, - "worst": 1, - "thresh": 0, - "raw_value": 3831, - "raw_string": "3831", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 315, - "CreatedAt": "2020-09-07T15:38:56.629382363Z", - "UpdatedAt": "2020-09-07T15:38:56.629382363Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 1, - "worst": 1, - "thresh": 0, - "raw_value": 3831, - "raw_string": "3831", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 262, - "CreatedAt": "2020-09-07T15:26:07.500933439Z", - "UpdatedAt": "2020-09-07T15:26:07.500933439Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 1, - "worst": 1, - "thresh": 0, - "raw_value": 3831, - "raw_string": "3831", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 209, - "CreatedAt": "2020-09-07T15:19:17.463228599Z", - "UpdatedAt": "2020-09-07T15:19:17.463228599Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 1, - "worst": 1, - "thresh": 0, - "raw_value": 3831, - "raw_string": "3831", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 156, - "CreatedAt": "2020-09-07T15:10:40.242496871Z", - "UpdatedAt": "2020-09-07T15:10:40.242496871Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 1, - "worst": 1, - "thresh": 0, - "raw_value": 3831, - "raw_string": "3831", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 103, - "CreatedAt": "2020-09-06T23:14:39.845209356Z", - "UpdatedAt": "2020-09-06T23:14:39.845209356Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 1, - "worst": 1, - "thresh": 0, - "raw_value": 3831, - "raw_string": "3831", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 50, - "CreatedAt": "2020-08-28T07:55:27.823890798Z", - "UpdatedAt": "2020-08-28T07:55:27.823890798Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 1, - "worst": 1, - "thresh": 0, - "raw_value": 3831, - "raw_string": "3831", - "when_failed": "", - "transformed_value": 0 - }] - }, { - "ID": 422, - "CreatedAt": "2020-09-08T21:39:26.570866-07:00", - "UpdatedAt": "2020-09-08T21:39:26.570866-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 197, - "name": "Current Pending Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 8, - "raw_string": "8", - "when_failed": "", - "transformed_value": 0, - "status": "failed", - "status_reason": "Observed Failure Rate for Critical Attribute is greater than 10%", - "failure_rate": 0.6108100007493069, - "history": [{ - "ID": 369, - "CreatedAt": "2020-09-07T15:47:21.332346697Z", - "UpdatedAt": "2020-09-07T15:47:21.332346697Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 197, - "name": "Current Pending Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 8, - "raw_string": "8", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 316, - "CreatedAt": "2020-09-07T15:38:56.629465264Z", - "UpdatedAt": "2020-09-07T15:38:56.629465264Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 197, - "name": "Current Pending Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 8, - "raw_string": "8", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 263, - "CreatedAt": "2020-09-07T15:26:07.501028141Z", - "UpdatedAt": "2020-09-07T15:26:07.501028141Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 197, - "name": "Current Pending Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 8, - "raw_string": "8", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 210, - "CreatedAt": "2020-09-07T15:19:17.463302498Z", - "UpdatedAt": "2020-09-07T15:19:17.463302498Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 197, - "name": "Current Pending Sector Count", + "name": "Read Error Rate", "value": 100, + "thresh": 16, "worst": 100, - "thresh": 0, - "raw_value": 8, - "raw_string": "8", + "raw_value": 0, + "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 157, - "CreatedAt": "2020-09-07T15:10:40.242564072Z", - "UpdatedAt": "2020-09-07T15:10:40.242564072Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 197, - "name": "Current Pending Sector Count", + }, + "10": { + "attribute_id": 10, + "name": "Spin Retry Count", "value": 100, + "thresh": 60, "worst": 100, - "thresh": 0, - "raw_value": 8, - "raw_string": "8", + "raw_value": 0, + "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 104, - "CreatedAt": "2020-09-06T23:14:39.845294758Z", - "UpdatedAt": "2020-09-06T23:14:39.845294758Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 197, - "name": "Current Pending Sector Count", + }, + "12": { + "attribute_id": 12, + "name": "Power Cycle Count", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 8, - "raw_string": "8", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 51, - "CreatedAt": "2020-08-28T07:55:27.823980673Z", - "UpdatedAt": "2020-08-28T07:55:27.823980673Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 197, - "name": "Current Pending Sector Count", - "value": 100, "worst": 100, - "thresh": 0, - "raw_value": 8, - "raw_string": "8", + "raw_value": 86, + "raw_string": "86", "when_failed": "", "transformed_value": 0 - }] - }, { - "ID": 423, - "CreatedAt": "2020-09-08T21:39:26.570936-07:00", - "UpdatedAt": "2020-09-08T21:39:26.570936-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.028675322159886437, - "history": [{ - "ID": 370, - "CreatedAt": "2020-09-07T15:47:21.332430997Z", - "UpdatedAt": "2020-09-07T15:47:21.332430997Z", - "DeletedAt": null, - "smart_id": 39, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", - "value": 100, - "worst": 100, + }, + "192": { + "attribute_id": 192, + "name": "Power-off Retract Count", + "value": 95, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 95, + "raw_value": 6244, + "raw_string": "6244", "when_failed": "", "transformed_value": 0 - }, { - "ID": 317, - "CreatedAt": "2020-09-07T15:38:56.629541365Z", - "UpdatedAt": "2020-09-07T15:38:56.629541365Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", - "value": 100, - "worst": 100, + }, + "193": { + "attribute_id": 193, + "name": "Load Cycle Count", + "value": 95, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 95, + "raw_value": 6244, + "raw_string": "6244", "when_failed": "", "transformed_value": 0 - }, { - "ID": 264, - "CreatedAt": "2020-09-07T15:26:07.501116944Z", - "UpdatedAt": "2020-09-07T15:26:07.501116944Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", - "value": 100, - "worst": 100, + }, + "194": { + "attribute_id": 194, + "name": "Temperature", + "value": 240, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 240, + "raw_value": 167504969753, + "raw_string": "25 (Min/Max 19/39)", "when_failed": "", "transformed_value": 0 - }, { - "ID": 211, - "CreatedAt": "2020-09-07T15:19:17.463380498Z", - "UpdatedAt": "2020-09-07T15:19:17.463380498Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", - "value": 100, - "worst": 100, + }, + "196": { + "attribute_id": 196, + "name": "Reallocation Event Count", + "value": 1, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 1, + "raw_value": 3831, + "raw_string": "3831", "when_failed": "", "transformed_value": 0 - }, { - "ID": 158, - "CreatedAt": "2020-09-07T15:10:40.242633572Z", - "UpdatedAt": "2020-09-07T15:10:40.242633572Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", + }, + "197": { + "attribute_id": 197, + "name": "Current Pending Sector Count", "value": 100, - "worst": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, { - "ID": 105, - "CreatedAt": "2020-09-06T23:14:39.84535416Z", - "UpdatedAt": "2020-09-06T23:14:39.84535416Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", - "value": 100, "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "raw_value": 8, + "raw_string": "8", "when_failed": "", "transformed_value": 0 - }, { - "ID": 52, - "CreatedAt": "2020-08-28T07:55:27.824077866Z", - "UpdatedAt": "2020-08-28T07:55:27.824077866Z", - "DeletedAt": null, - "smart_id": 3, + }, + "198": { "attribute_id": 198, "name": "(Offline) Uncorrectable Sector Count", "value": 100, - "worst": 100, "thresh": 0, + "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }] - }, { - "ID": 424, - "CreatedAt": "2020-09-08T21:39:26.571034-07:00", - "UpdatedAt": "2020-09-08T21:39:26.571034-07:00", - "DeletedAt": null, - "smart_id": 45, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", - "value": 200, - "worst": 200, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 371, - "CreatedAt": "2020-09-07T15:47:21.332512198Z", - "UpdatedAt": "2020-09-07T15:47:21.332512198Z", - "DeletedAt": null, - "smart_id": 39, + }, + "199": { "attribute_id": 199, "name": "UltraDMA CRC Error Count", "value": 200, - "worst": 200, "thresh": 0, + "worst": 200, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 318, - "CreatedAt": "2020-09-07T15:38:56.629610265Z", - "UpdatedAt": "2020-09-07T15:38:56.629610265Z", - "DeletedAt": null, - "smart_id": 33, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", - "value": 200, - "worst": 200, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", + }, + "2": { + "attribute_id": 2, + "name": "Throughput Performance", + "value": 136, + "thresh": 54, + "worst": 136, + "raw_value": 91, + "raw_string": "91", "when_failed": "", "transformed_value": 0 - }, { - "ID": 265, - "CreatedAt": "2020-09-07T15:26:07.501203046Z", - "UpdatedAt": "2020-09-07T15:26:07.501203046Z", - "DeletedAt": null, - "smart_id": 27, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", - "value": 200, - "worst": 200, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", + }, + "3": { + "attribute_id": 3, + "name": "Spin-Up Time", + "value": 125, + "thresh": 24, + "worst": 125, + "raw_value": 17192124596, + "raw_string": "180 (Average 187)", "when_failed": "", "transformed_value": 0 - }, { - "ID": 212, - "CreatedAt": "2020-09-07T15:19:17.463463398Z", - "UpdatedAt": "2020-09-07T15:19:17.463463398Z", - "DeletedAt": null, - "smart_id": 21, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", - "value": 200, - "worst": 200, + }, + "4": { + "attribute_id": 4, + "name": "Start/Stop Count", + "value": 100, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 100, + "raw_value": 86, + "raw_string": "86", "when_failed": "", "transformed_value": 0 - }, { - "ID": 159, - "CreatedAt": "2020-09-07T15:10:40.242702673Z", - "UpdatedAt": "2020-09-07T15:10:40.242702673Z", - "DeletedAt": null, - "smart_id": 15, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", - "value": 200, - "worst": 200, - "thresh": 0, + }, + "5": { + "attribute_id": 5, + "name": "Reallocated Sectors Count", + "value": 1, + "thresh": 5, + "worst": 1, + "raw_value": 1975, + "raw_string": "1975", + "when_failed": "now", + "transformed_value": 0 + }, + "7": { + "attribute_id": 7, + "name": "Seek Error Rate", + "value": 100, + "thresh": 67, + "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", "transformed_value": 0 - }, { - "ID": 106, - "CreatedAt": "2020-09-06T23:14:39.845437463Z", - "UpdatedAt": "2020-09-06T23:14:39.845437463Z", - "DeletedAt": null, - "smart_id": 9, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", - "value": 200, - "worst": 200, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", + }, + "8": { + "attribute_id": 8, + "name": "Seek Time Performance", + "value": 118, + "thresh": 20, + "worst": 118, + "raw_value": 33, + "raw_string": "33", "when_failed": "", "transformed_value": 0 - }, { - "ID": 53, - "CreatedAt": "2020-08-28T07:55:27.824166466Z", - "UpdatedAt": "2020-08-28T07:55:27.824166466Z", - "DeletedAt": null, - "smart_id": 3, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", - "value": 200, - "worst": 200, + }, + "9": { + "attribute_id": 9, + "name": "Power-On Hours", + "value": 91, "thresh": 0, - "raw_value": 0, - "raw_string": "0", + "worst": 91, + "raw_value": 65592, + "raw_string": "65592", "when_failed": "", "transformed_value": 0 - }] - }], - "nvme_attributes": [], - "scsi_attributes": [] + } + } }] - }, "metadata": { + }, + "metadata": { "1": { "ideal": "low", "critical": false, @@ -2141,12 +240,22 @@ export const sdc = { "high": 125, "annual_failure_rate": 0.06390002135229157, "error_interval": [0.05852004676110847, 0.06964160930553712] - }, {"low": 125, "high": 140, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 125, + "high": 140, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 140, "high": 155, "annual_failure_rate": 0, "error_interval": [0, 0] - }, {"low": 155, "high": 170, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 155, + "high": 170, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 170, "high": 185, "annual_failure_rate": 0, @@ -2190,17 +299,32 @@ export const sdc = { "high": 80, "annual_failure_rate": 0.5555555555555556, "error_interval": [0.014065448880161053, 3.095357439410498] - }, {"low": 80, "high": 160, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 80, + "high": 160, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 160, "high": 240, "annual_failure_rate": 0, "error_interval": [0, 0] - }, {"low": 240, "high": 320, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 240, + "high": 320, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 320, "high": 400, "annual_failure_rate": 0, "error_interval": [0, 0] - }, {"low": 400, "high": 480, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 400, + "high": 480, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 480, "high": 560, "annual_failure_rate": 0, @@ -2256,7 +380,12 @@ export const sdc = { "description": "Uncorrected read errors reported to the operating system.", "display_type": "normalized" }, - "170": {"ideal": "", "critical": false, "description": "See attribute E8.", "display_type": "normalized"}, + "170": { + "ideal": "", + "critical": false, + "description": "See attribute E8.", + "display_type": "normalized" + }, "171": { "ideal": "", "critical": false, @@ -2367,7 +496,12 @@ export const sdc = { "high": 130, "annual_failure_rate": 0.40299684542586756, "error_interval": [0.16202563309223209, 0.8303275247667772] - }, {"low": 130, "high": 260, "annual_failure_rate": 0, "error_interval": [0, 0]}], + }, { + "low": 130, + "high": 260, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }], "display_type": "raw" }, "184": { @@ -2379,12 +513,22 @@ export const sdc = { "high": 94, "annual_failure_rate": 1.631212012870933, "error_interval": [1.055634407303844, 2.407990716767714] - }, {"low": 94, "high": 95, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 94, + "high": 95, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 95, "high": 96, "annual_failure_rate": 0, "error_interval": [0, 0] - }, {"low": 96, "high": 97, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 96, + "high": 97, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 97, "high": 97, "annual_failure_rate": 0, @@ -2666,12 +810,22 @@ export const sdc = { "high": 60, "annual_failure_rate": 0.05672658497265746, "error_interval": [0.043182904776447234, 0.07317316161437043] - }, {"low": 60, "high": 72, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 60, + "high": 72, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 72, "high": 84, "annual_failure_rate": 0, "error_interval": [0, 0] - }, {"low": 84, "high": 96, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 84, + "high": 96, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 96, "high": 108, "annual_failure_rate": 0.04074570216566197, @@ -3213,7 +1367,12 @@ export const sdc = { "high": 91, "annual_failure_rate": 0.12262136155304391, "error_interval": [0.0670382394080032, 0.20573780888032978] - }, {"low": 91, "high": 104, "annual_failure_rate": 0, "error_interval": [0, 0]}], + }, { + "low": 91, + "high": 104, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }], "display_type": "raw" }, "5": { @@ -3293,12 +1452,22 @@ export const sdc = { "high": 112, "annual_failure_rate": 0.01087335627722523, "error_interval": [0.008732197944943352, 0.013380600544561905] - }, {"low": 112, "high": 130, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 112, + "high": 130, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 130, "high": 148, "annual_failure_rate": 0, "error_interval": [0, 0] - }, {"low": 148, "high": 166, "annual_failure_rate": 0, "error_interval": [0, 0]}, { + }, { + "low": 148, + "high": 166, + "annual_failure_rate": 0, + "error_interval": [0, 0] + }, { "low": 166, "high": 184, "annual_failure_rate": 0, @@ -3323,5 +1492,6 @@ export const sdc = { "description": "Count of hours in power-on state. The raw value of this attribute shows total count of hours (or minutes, or seconds, depending on manufacturer) in power-on state. By default, the total expected lifetime of a hard disk in perfect condition is defined as 5 years (running every day and night on all days). This is equal to 1825 days in 24/7 mode or 43800 hours. On some pre-2005 drives, this raw value may advance erratically and/or \"wrap around\" (reset to zero periodically).", "display_type": "normalized" } - }, "success": true + }, + "success": true } diff --git a/webapp/frontend/src/app/data/mock/device/details/sdd.ts b/webapp/frontend/src/app/data/mock/device/details/sdd.ts index 5884342..35e73d1 100644 --- a/webapp/frontend/src/app/data/mock/device/details/sdd.ts +++ b/webapp/frontend/src/app/data/mock/device/details/sdd.ts @@ -1,1240 +1,208 @@ export const sdd = { "data": { - "CreatedAt": "2020-08-28T07:55:27.76380029Z", - "UpdatedAt": "2020-09-08T21:39:26.575283-07:00", - "DeletedAt": null, - "wwn": "0x5000cca252c859cc", - "device_name": "sdd", - "manufacturer": "SEAGATE", - "model_name": "WDC_WD80EFAX-68LHPN0", - "interface_type": "SCSI", - "interface_speed": "", - "serial_number": "7SGLXXXXX", - "firmware": "", - "rotational_speed": 7200, - "capacity": 4000787030016, - "form_factor": "3.5 inches", - "smart_support": false, - "device_protocol": "SCSI", - "device_type": "scsi", - "smart_results": [{ - "ID": 47, - "CreatedAt": "2020-09-08T21:39:26.576373-07:00", - "UpdatedAt": "2020-09-08T21:39:26.576373-07:00", + "device": { + "CreatedAt": "2021-06-24T21:17:31.30374-07:00", + "UpdatedAt": "2021-06-26T14:26:20.902325-07:00", "DeletedAt": null, + "wwn": "0x5000cca252c859cc", + "device_name": "sdd", + "manufacturer": "ATA", + "model_name": "WDC_WD80EFAX-68LHPN0", + "interface_type": "SCSI", + "interface_speed": "", + "serial_number": "7SGLXXXXX", + "firmware": "", + "rotational_speed": 0, + "capacity": 8001563222016, + "form_factor": "", + "smart_support": false, + "device_protocol": "SCSI", + "device_type": "", + "label": "", + "host_id": "", + "device_status": 0 + }, + "smart_results": [{ + "date": "2020-08-21T22:27:02Z", "device_wwn": "0x5000cca252c859cc", - "date": "2020-08-21T15:27:02-07:00", - "smart_status": "passed", + "device_protocol": "SCSI", "temp": 34, "power_on_hours": 43549, "power_cycle_count": 0, - "ata_attributes": [], - "nvme_attributes": [], - "scsi_attributes": [{ - "ID": 183, - "CreatedAt": "2020-09-08T21:39:26.576671-07:00", - "UpdatedAt": "2020-09-08T21:39:26.576671-07:00", - "DeletedAt": null, - "smart_id": 47, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 56, - "thresh": 0, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 157, - "CreatedAt": "2020-09-07T15:47:21.34270442Z", - "UpdatedAt": "2020-09-07T15:47:21.34270442Z", - "DeletedAt": null, - "smart_id": 41, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 56, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 131, - "CreatedAt": "2020-09-07T15:38:56.63806264Z", - "UpdatedAt": "2020-09-07T15:38:56.63806264Z", - "DeletedAt": null, - "smart_id": 35, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 56, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 105, - "CreatedAt": "2020-09-07T15:26:07.511359323Z", - "UpdatedAt": "2020-09-07T15:26:07.511359323Z", - "DeletedAt": null, - "smart_id": 29, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 56, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 79, - "CreatedAt": "2020-09-07T15:19:17.472566367Z", - "UpdatedAt": "2020-09-07T15:19:17.472566367Z", - "DeletedAt": null, - "smart_id": 23, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 56, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 53, - "CreatedAt": "2020-09-07T15:10:40.252068341Z", - "UpdatedAt": "2020-09-07T15:10:40.252068341Z", - "DeletedAt": null, - "smart_id": 17, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 56, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 27, - "CreatedAt": "2020-09-06T23:14:39.854497534Z", - "UpdatedAt": "2020-09-06T23:14:39.854497534Z", - "DeletedAt": null, - "smart_id": 11, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 56, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 1, - "CreatedAt": "2020-08-28T07:55:27.845073051Z", - "UpdatedAt": "2020-08-28T07:55:27.845073051Z", - "DeletedAt": null, - "smart_id": 5, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 56, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 184, - "CreatedAt": "2020-09-08T21:39:26.577142-07:00", - "UpdatedAt": "2020-09-08T21:39:26.577142-07:00", - "DeletedAt": null, - "smart_id": 47, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 300357663, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 158, - "CreatedAt": "2020-09-07T15:47:21.34285782Z", - "UpdatedAt": "2020-09-07T15:47:21.34285782Z", - "DeletedAt": null, - "smart_id": 41, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 300357663, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 132, - "CreatedAt": "2020-09-07T15:38:56.638194141Z", - "UpdatedAt": "2020-09-07T15:38:56.638194141Z", - "DeletedAt": null, - "smart_id": 35, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 300357663, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 106, - "CreatedAt": "2020-09-07T15:26:07.511676732Z", - "UpdatedAt": "2020-09-07T15:26:07.511676732Z", - "DeletedAt": null, - "smart_id": 29, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 300357663, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 80, - "CreatedAt": "2020-09-07T15:19:17.472704067Z", - "UpdatedAt": "2020-09-07T15:19:17.472704067Z", - "DeletedAt": null, - "smart_id": 23, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 300357663, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 54, - "CreatedAt": "2020-09-07T15:10:40.252408443Z", - "UpdatedAt": "2020-09-07T15:10:40.252408443Z", - "DeletedAt": null, - "smart_id": 17, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 300357663, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 28, - "CreatedAt": "2020-09-06T23:14:39.854629938Z", - "UpdatedAt": "2020-09-06T23:14:39.854629938Z", - "DeletedAt": null, - "smart_id": 11, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 300357663, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 2, - "CreatedAt": "2020-08-28T07:55:27.845217252Z", - "UpdatedAt": "2020-08-28T07:55:27.845217252Z", - "DeletedAt": null, - "smart_id": 5, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 300357663, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 185, - "CreatedAt": "2020-09-08T21:39:26.577223-07:00", - "UpdatedAt": "2020-09-08T21:39:26.577223-07:00", - "DeletedAt": null, - "smart_id": 47, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 159, - "CreatedAt": "2020-09-07T15:47:21.342970521Z", - "UpdatedAt": "2020-09-07T15:47:21.342970521Z", - "DeletedAt": null, - "smart_id": 41, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 133, - "CreatedAt": "2020-09-07T15:38:56.638272842Z", - "UpdatedAt": "2020-09-07T15:38:56.638272842Z", - "DeletedAt": null, - "smart_id": 35, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 107, - "CreatedAt": "2020-09-07T15:26:07.511771334Z", - "UpdatedAt": "2020-09-07T15:26:07.511771334Z", - "DeletedAt": null, - "smart_id": 29, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 81, - "CreatedAt": "2020-09-07T15:19:17.472780267Z", - "UpdatedAt": "2020-09-07T15:19:17.472780267Z", - "DeletedAt": null, - "smart_id": 23, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 55, - "CreatedAt": "2020-09-07T15:10:40.252543044Z", - "UpdatedAt": "2020-09-07T15:10:40.252543044Z", - "DeletedAt": null, - "smart_id": 17, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 29, - "CreatedAt": "2020-09-06T23:14:39.85470424Z", - "UpdatedAt": "2020-09-06T23:14:39.85470424Z", - "DeletedAt": null, - "smart_id": 11, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", + "attrs": { + "read_correction_algorithm_invocations": { + "attribute_id": "read_correction_algorithm_invocations", + "name": "Read Correction Algorithm Invocations", "value": 0, - "thresh": 0, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 3, - "CreatedAt": "2020-08-28T07:55:27.845307694Z", - "UpdatedAt": "2020-08-28T07:55:27.845307694Z", - "DeletedAt": null, - "smart_id": 5, - "attribute_id": "read.errors_corrected_by_eccdelayed", + }, + "read_errors_corrected_by_eccdelayed": { + "attribute_id": "read_errors_corrected_by_eccdelayed", "name": "Read Errors Corrected by ECC Delayed", "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 186, - "CreatedAt": "2020-09-08T21:39:26.577322-07:00", - "UpdatedAt": "2020-09-08T21:39:26.577322-07:00", - "DeletedAt": null, - "smart_id": 47, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 160, - "CreatedAt": "2020-09-07T15:47:21.343052321Z", - "UpdatedAt": "2020-09-07T15:47:21.343052321Z", - "DeletedAt": null, - "smart_id": 41, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 134, - "CreatedAt": "2020-09-07T15:38:56.638349442Z", - "UpdatedAt": "2020-09-07T15:38:56.638349442Z", - "DeletedAt": null, - "smart_id": 35, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 108, - "CreatedAt": "2020-09-07T15:26:07.512120944Z", - "UpdatedAt": "2020-09-07T15:26:07.512120944Z", - "DeletedAt": null, - "smart_id": 29, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 82, - "CreatedAt": "2020-09-07T15:19:17.472863366Z", - "UpdatedAt": "2020-09-07T15:19:17.472863366Z", - "DeletedAt": null, - "smart_id": 23, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 56, - "CreatedAt": "2020-09-07T15:10:40.252654845Z", - "UpdatedAt": "2020-09-07T15:10:40.252654845Z", - "DeletedAt": null, - "smart_id": 17, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 30, - "CreatedAt": "2020-09-06T23:14:39.854773542Z", - "UpdatedAt": "2020-09-06T23:14:39.854773542Z", - "DeletedAt": null, - "smart_id": 11, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, + }, + "read_errors_corrected_by_eccfast": { + "attribute_id": "read_errors_corrected_by_eccfast", + "name": "Read Errors Corrected by ECC Fast", + "value": 300357663, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 4, - "CreatedAt": "2020-08-28T07:55:27.845417944Z", - "UpdatedAt": "2020-08-28T07:55:27.845417944Z", - "DeletedAt": null, - "smart_id": 5, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", + }, + "read_errors_corrected_by_rereads_rewrites": { + "attribute_id": "read_errors_corrected_by_rereads_rewrites", "name": "Read Errors Corrected by ReReads/ReWrites", "value": 0, "thresh": 0, "transformed_value": 0 - }] - }, { - "ID": 187, - "CreatedAt": "2020-09-08T21:39:26.577402-07:00", - "UpdatedAt": "2020-09-08T21:39:26.577402-07:00", - "DeletedAt": null, - "smart_id": 47, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", - "value": 300357663, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 161, - "CreatedAt": "2020-09-07T15:47:21.343130621Z", - "UpdatedAt": "2020-09-07T15:47:21.343130621Z", - "DeletedAt": null, - "smart_id": 41, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", - "value": 300357663, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 135, - "CreatedAt": "2020-09-07T15:38:56.638419243Z", - "UpdatedAt": "2020-09-07T15:38:56.638419243Z", - "DeletedAt": null, - "smart_id": 35, - "attribute_id": "read.total_errors_corrected", + }, + "read_total_errors_corrected": { + "attribute_id": "read_total_errors_corrected", "name": "Read Total Errors Corrected", "value": 300357663, - "thresh": 0, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 109, - "CreatedAt": "2020-09-07T15:26:07.512289049Z", - "UpdatedAt": "2020-09-07T15:26:07.512289049Z", - "DeletedAt": null, - "smart_id": 29, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", - "value": 300357663, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 83, - "CreatedAt": "2020-09-07T15:19:17.472931366Z", - "UpdatedAt": "2020-09-07T15:19:17.472931366Z", - "DeletedAt": null, - "smart_id": 23, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", - "value": 300357663, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 57, - "CreatedAt": "2020-09-07T15:10:40.252764246Z", - "UpdatedAt": "2020-09-07T15:10:40.252764246Z", - "DeletedAt": null, - "smart_id": 17, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", - "value": 300357663, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 31, - "CreatedAt": "2020-09-06T23:14:39.854857145Z", - "UpdatedAt": "2020-09-06T23:14:39.854857145Z", - "DeletedAt": null, - "smart_id": 11, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", - "value": 300357663, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 5, - "CreatedAt": "2020-08-28T07:55:27.84550537Z", - "UpdatedAt": "2020-08-28T07:55:27.84550537Z", - "DeletedAt": null, - "smart_id": 5, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", - "value": 300357663, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 188, - "CreatedAt": "2020-09-08T21:39:26.577467-07:00", - "UpdatedAt": "2020-09-08T21:39:26.577467-07:00", - "DeletedAt": null, - "smart_id": 47, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 162, - "CreatedAt": "2020-09-07T15:47:21.343232021Z", - "UpdatedAt": "2020-09-07T15:47:21.343232021Z", - "DeletedAt": null, - "smart_id": 41, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 136, - "CreatedAt": "2020-09-07T15:38:56.638492144Z", - "UpdatedAt": "2020-09-07T15:38:56.638492144Z", - "DeletedAt": null, - "smart_id": 35, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 110, - "CreatedAt": "2020-09-07T15:26:07.512411952Z", - "UpdatedAt": "2020-09-07T15:26:07.512411952Z", - "DeletedAt": null, - "smart_id": 29, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 84, - "CreatedAt": "2020-09-07T15:19:17.473000166Z", - "UpdatedAt": "2020-09-07T15:19:17.473000166Z", - "DeletedAt": null, - "smart_id": 23, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 58, - "CreatedAt": "2020-09-07T15:10:40.252885147Z", - "UpdatedAt": "2020-09-07T15:10:40.252885147Z", - "DeletedAt": null, - "smart_id": 17, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 32, - "CreatedAt": "2020-09-06T23:14:39.854921646Z", - "UpdatedAt": "2020-09-06T23:14:39.854921646Z", - "DeletedAt": null, - "smart_id": 11, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 6, - "CreatedAt": "2020-08-28T07:55:27.845607015Z", - "UpdatedAt": "2020-08-28T07:55:27.845607015Z", - "DeletedAt": null, - "smart_id": 5, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 189, - "CreatedAt": "2020-09-08T21:39:26.577528-07:00", - "UpdatedAt": "2020-09-08T21:39:26.577528-07:00", - "DeletedAt": null, - "smart_id": 47, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 163, - "CreatedAt": "2020-09-07T15:47:21.343302621Z", - "UpdatedAt": "2020-09-07T15:47:21.343302621Z", - "DeletedAt": null, - "smart_id": 41, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 137, - "CreatedAt": "2020-09-07T15:38:56.638557144Z", - "UpdatedAt": "2020-09-07T15:38:56.638557144Z", - "DeletedAt": null, - "smart_id": 35, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 111, - "CreatedAt": "2020-09-07T15:26:07.512526855Z", - "UpdatedAt": "2020-09-07T15:26:07.512526855Z", - "DeletedAt": null, - "smart_id": 29, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 85, - "CreatedAt": "2020-09-07T15:19:17.473078066Z", - "UpdatedAt": "2020-09-07T15:19:17.473078066Z", - "DeletedAt": null, - "smart_id": 23, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 59, - "CreatedAt": "2020-09-07T15:10:40.252987648Z", - "UpdatedAt": "2020-09-07T15:10:40.252987648Z", - "DeletedAt": null, - "smart_id": 17, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 33, - "CreatedAt": "2020-09-06T23:14:39.854986748Z", - "UpdatedAt": "2020-09-06T23:14:39.854986748Z", - "DeletedAt": null, - "smart_id": 11, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 7, - "CreatedAt": "2020-08-28T07:55:27.845686961Z", - "UpdatedAt": "2020-08-28T07:55:27.845686961Z", - "DeletedAt": null, - "smart_id": 5, - "attribute_id": "read.total_uncorrected_errors", + }, + "read_total_uncorrected_errors": { + "attribute_id": "read_total_uncorrected_errors", "name": "Read Total Uncorrected Errors", "value": 0, "thresh": 0, "transformed_value": 0 - }] - }, { - "ID": 190, - "CreatedAt": "2020-09-08T21:39:26.577585-07:00", - "UpdatedAt": "2020-09-08T21:39:26.577585-07:00", - "DeletedAt": null, - "smart_id": 47, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 164, - "CreatedAt": "2020-09-07T15:47:21.343385821Z", - "UpdatedAt": "2020-09-07T15:47:21.343385821Z", - "DeletedAt": null, - "smart_id": 41, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 138, - "CreatedAt": "2020-09-07T15:38:56.638623345Z", - "UpdatedAt": "2020-09-07T15:38:56.638623345Z", - "DeletedAt": null, - "smart_id": 35, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 112, - "CreatedAt": "2020-09-07T15:26:07.51269696Z", - "UpdatedAt": "2020-09-07T15:26:07.51269696Z", - "DeletedAt": null, - "smart_id": 29, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 86, - "CreatedAt": "2020-09-07T15:19:17.473144665Z", - "UpdatedAt": "2020-09-07T15:19:17.473144665Z", - "DeletedAt": null, - "smart_id": 23, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 60, - "CreatedAt": "2020-09-07T15:10:40.253104448Z", - "UpdatedAt": "2020-09-07T15:10:40.253104448Z", - "DeletedAt": null, - "smart_id": 17, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 34, - "CreatedAt": "2020-09-06T23:14:39.85505285Z", - "UpdatedAt": "2020-09-06T23:14:39.85505285Z", - "DeletedAt": null, - "smart_id": 11, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 8, - "CreatedAt": "2020-08-28T07:55:27.845805078Z", - "UpdatedAt": "2020-08-28T07:55:27.845805078Z", - "DeletedAt": null, - "smart_id": 5, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 191, - "CreatedAt": "2020-09-08T21:39:26.577642-07:00", - "UpdatedAt": "2020-09-08T21:39:26.577642-07:00", - "DeletedAt": null, - "smart_id": 47, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 165, - "CreatedAt": "2020-09-07T15:47:21.343465022Z", - "UpdatedAt": "2020-09-07T15:47:21.343465022Z", - "DeletedAt": null, - "smart_id": 41, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 139, - "CreatedAt": "2020-09-07T15:38:56.638687045Z", - "UpdatedAt": "2020-09-07T15:38:56.638687045Z", - "DeletedAt": null, - "smart_id": 35, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 113, - "CreatedAt": "2020-09-07T15:26:07.512816463Z", - "UpdatedAt": "2020-09-07T15:26:07.512816463Z", - "DeletedAt": null, - "smart_id": 29, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 87, - "CreatedAt": "2020-09-07T15:19:17.473246965Z", - "UpdatedAt": "2020-09-07T15:19:17.473246965Z", - "DeletedAt": null, - "smart_id": 23, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, + }, + "scsi_grown_defect_list": { + "attribute_id": "scsi_grown_defect_list", + "name": "Grown Defect List", + "value": 56, "thresh": 0, "transformed_value": 0 - }, { - "ID": 61, - "CreatedAt": "2020-09-07T15:10:40.253434751Z", - "UpdatedAt": "2020-09-07T15:10:40.253434751Z", - "DeletedAt": null, - "smart_id": 17, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", + }, + "write_correction_algorithm_invocations": { + "attribute_id": "write_correction_algorithm_invocations", + "name": "Write Correction Algorithm Invocations", "value": 0, - "thresh": 0, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 35, - "CreatedAt": "2020-09-06T23:14:39.855116452Z", - "UpdatedAt": "2020-09-06T23:14:39.855116452Z", - "DeletedAt": null, - "smart_id": 11, - "attribute_id": "write.errors_corrected_by_eccdelayed", + }, + "write_errors_corrected_by_eccdelayed": { + "attribute_id": "write_errors_corrected_by_eccdelayed", "name": "Write Errors Corrected by ECC Delayed", "value": 0, - "thresh": 0, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 9, - "CreatedAt": "2020-08-28T07:55:27.846267863Z", - "UpdatedAt": "2020-08-28T07:55:27.846267863Z", - "DeletedAt": null, - "smart_id": 5, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 192, - "CreatedAt": "2020-09-08T21:39:26.577699-07:00", - "UpdatedAt": "2020-09-08T21:39:26.577699-07:00", - "DeletedAt": null, - "smart_id": 47, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 166, - "CreatedAt": "2020-09-07T15:47:21.343534322Z", - "UpdatedAt": "2020-09-07T15:47:21.343534322Z", - "DeletedAt": null, - "smart_id": 41, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 140, - "CreatedAt": "2020-09-07T15:38:56.638979448Z", - "UpdatedAt": "2020-09-07T15:38:56.638979448Z", - "DeletedAt": null, - "smart_id": 35, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 114, - "CreatedAt": "2020-09-07T15:26:07.513298876Z", - "UpdatedAt": "2020-09-07T15:26:07.513298876Z", - "DeletedAt": null, - "smart_id": 29, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 88, - "CreatedAt": "2020-09-07T15:19:17.473324965Z", - "UpdatedAt": "2020-09-07T15:19:17.473324965Z", - "DeletedAt": null, - "smart_id": 23, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 62, - "CreatedAt": "2020-09-07T15:10:40.253539552Z", - "UpdatedAt": "2020-09-07T15:10:40.253539552Z", - "DeletedAt": null, - "smart_id": 17, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 36, - "CreatedAt": "2020-09-06T23:14:39.855181654Z", - "UpdatedAt": "2020-09-06T23:14:39.855181654Z", - "DeletedAt": null, - "smart_id": 11, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", + }, + "write_errors_corrected_by_eccfast": { + "attribute_id": "write_errors_corrected_by_eccfast", + "name": "Write Errors Corrected by ECC Fast", "value": 0, - "thresh": 0, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 10, - "CreatedAt": "2020-08-28T07:55:27.846466097Z", - "UpdatedAt": "2020-08-28T07:55:27.846466097Z", - "DeletedAt": null, - "smart_id": 5, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", + }, + "write_errors_corrected_by_rereads_rewrites": { + "attribute_id": "write_errors_corrected_by_rereads_rewrites", "name": "Write Errors Corrected by ReReads/ReWrites", "value": 0, "thresh": 0, "transformed_value": 0 - }] - }, { - "ID": 193, - "CreatedAt": "2020-09-08T21:39:26.577768-07:00", - "UpdatedAt": "2020-09-08T21:39:26.577768-07:00", - "DeletedAt": null, - "smart_id": 47, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 167, - "CreatedAt": "2020-09-07T15:47:21.343602322Z", - "UpdatedAt": "2020-09-07T15:47:21.343602322Z", - "DeletedAt": null, - "smart_id": 41, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 141, - "CreatedAt": "2020-09-07T15:38:56.639119449Z", - "UpdatedAt": "2020-09-07T15:38:56.639119449Z", - "DeletedAt": null, - "smart_id": 35, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 115, - "CreatedAt": "2020-09-07T15:26:07.513392579Z", - "UpdatedAt": "2020-09-07T15:26:07.513392579Z", - "DeletedAt": null, - "smart_id": 29, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 89, - "CreatedAt": "2020-09-07T15:19:17.473396265Z", - "UpdatedAt": "2020-09-07T15:19:17.473396265Z", - "DeletedAt": null, - "smart_id": 23, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 63, - "CreatedAt": "2020-09-07T15:10:40.253617252Z", - "UpdatedAt": "2020-09-07T15:10:40.253617252Z", - "DeletedAt": null, - "smart_id": 17, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 37, - "CreatedAt": "2020-09-06T23:14:39.855245056Z", - "UpdatedAt": "2020-09-06T23:14:39.855245056Z", - "DeletedAt": null, - "smart_id": 11, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 11, - "CreatedAt": "2020-08-28T07:55:27.846680695Z", - "UpdatedAt": "2020-08-28T07:55:27.846680695Z", - "DeletedAt": null, - "smart_id": 5, - "attribute_id": "write.total_errors_corrected", + }, + "write_total_errors_corrected": { + "attribute_id": "write_total_errors_corrected", "name": "Write Total Errors Corrected", "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 194, - "CreatedAt": "2020-09-08T21:39:26.577827-07:00", - "UpdatedAt": "2020-09-08T21:39:26.577827-07:00", - "DeletedAt": null, - "smart_id": 47, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 168, - "CreatedAt": "2020-09-07T15:47:21.343669122Z", - "UpdatedAt": "2020-09-07T15:47:21.343669122Z", - "DeletedAt": null, - "smart_id": 41, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 142, - "CreatedAt": "2020-09-07T15:38:56.63923905Z", - "UpdatedAt": "2020-09-07T15:38:56.63923905Z", - "DeletedAt": null, - "smart_id": 35, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 116, - "CreatedAt": "2020-09-07T15:26:07.513473381Z", - "UpdatedAt": "2020-09-07T15:26:07.513473381Z", - "DeletedAt": null, - "smart_id": 29, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 90, - "CreatedAt": "2020-09-07T15:19:17.473465964Z", - "UpdatedAt": "2020-09-07T15:19:17.473465964Z", - "DeletedAt": null, - "smart_id": 23, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 64, - "CreatedAt": "2020-09-07T15:10:40.253699153Z", - "UpdatedAt": "2020-09-07T15:10:40.253699153Z", - "DeletedAt": null, - "smart_id": 17, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 38, - "CreatedAt": "2020-09-06T23:14:39.855310158Z", - "UpdatedAt": "2020-09-06T23:14:39.855310158Z", - "DeletedAt": null, - "smart_id": 11, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 12, - "CreatedAt": "2020-08-28T07:55:27.847304842Z", - "UpdatedAt": "2020-08-28T07:55:27.847304842Z", - "DeletedAt": null, - "smart_id": 5, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 195, - "CreatedAt": "2020-09-08T21:39:26.577884-07:00", - "UpdatedAt": "2020-09-08T21:39:26.577884-07:00", - "DeletedAt": null, - "smart_id": 47, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 169, - "CreatedAt": "2020-09-07T15:47:21.343735222Z", - "UpdatedAt": "2020-09-07T15:47:21.343735222Z", - "DeletedAt": null, - "smart_id": 41, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 143, - "CreatedAt": "2020-09-07T15:38:56.639331551Z", - "UpdatedAt": "2020-09-07T15:38:56.639331551Z", - "DeletedAt": null, - "smart_id": 35, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 117, - "CreatedAt": "2020-09-07T15:26:07.513551783Z", - "UpdatedAt": "2020-09-07T15:26:07.513551783Z", - "DeletedAt": null, - "smart_id": 29, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 91, - "CreatedAt": "2020-09-07T15:19:17.473531164Z", - "UpdatedAt": "2020-09-07T15:19:17.473531164Z", - "DeletedAt": null, - "smart_id": 23, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 65, - "CreatedAt": "2020-09-07T15:10:40.253767653Z", - "UpdatedAt": "2020-09-07T15:10:40.253767653Z", - "DeletedAt": null, - "smart_id": 17, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, + "thresh": -1, "transformed_value": 0 - }, { - "ID": 39, - "CreatedAt": "2020-09-06T23:14:39.85537276Z", - "UpdatedAt": "2020-09-06T23:14:39.85537276Z", - "DeletedAt": null, - "smart_id": 11, - "attribute_id": "write.total_uncorrected_errors", + }, + "write_total_uncorrected_errors": { + "attribute_id": "write_total_uncorrected_errors", "name": "Write Total Uncorrected Errors", "value": 0, "thresh": 0, "transformed_value": 0 - }, { - "ID": 13, - "CreatedAt": "2020-08-28T07:55:27.847458217Z", - "UpdatedAt": "2020-08-28T07:55:27.847458217Z", - "DeletedAt": null, - "smart_id": 5, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }] + } + } }] - }, "metadata": { - "read.correction_algorithm_invocations": { + }, + "metadata": { + "read_correction_algorithm_invocations": { + "ideal": "", + "critical": false, + "description": "", + "display_type": "" + }, + "read_errors_corrected_by_eccdelayed": { + "ideal": "", + "critical": false, + "description": "", + "display_type": "" + }, + "read_errors_corrected_by_eccfast": { + "ideal": "", + "critical": false, + "description": "", + "display_type": "" + }, + "read_errors_corrected_by_rereads_rewrites": { + "ideal": "low", + "critical": true, + "description": "", + "display_type": "" + }, + "read_total_errors_corrected": { "ideal": "", "critical": false, "description": "", "display_type": "" }, - "read.errors_corrected_by_eccdelayed": {"ideal": "", "critical": false, "description": "", "display_type": ""}, - "read.errors_corrected_by_eccfast": {"ideal": "", "critical": false, "description": "", "display_type": ""}, - "read.errors_corrected_by_rereads_rewrites": { + "read_total_uncorrected_errors": { "ideal": "low", "critical": true, "description": "", "display_type": "" }, - "read.total_errors_corrected": {"ideal": "", "critical": false, "description": "", "display_type": ""}, - "read.total_uncorrected_errors": {"ideal": "low", "critical": true, "description": "", "display_type": ""}, - "scsi_grown_defect_list": {"ideal": "low", "critical": true, "description": "", "display_type": ""}, - "write.correction_algorithm_invocations": { + "scsi_grown_defect_list": { + "ideal": "low", + "critical": true, + "description": "", + "display_type": "" + }, + "write_correction_algorithm_invocations": { + "ideal": "", + "critical": false, + "description": "", + "display_type": "" + }, + "write_errors_corrected_by_eccdelayed": { + "ideal": "", + "critical": false, + "description": "", + "display_type": "" + }, + "write_errors_corrected_by_eccfast": { "ideal": "", "critical": false, "description": "", "display_type": "" }, - "write.errors_corrected_by_eccdelayed": {"ideal": "", "critical": false, "description": "", "display_type": ""}, - "write.errors_corrected_by_eccfast": {"ideal": "", "critical": false, "description": "", "display_type": ""}, - "write.errors_corrected_by_rereads_rewrites": { + "write_errors_corrected_by_rereads_rewrites": { "ideal": "low", "critical": true, "description": "", "display_type": "" }, - "write.total_errors_corrected": {"ideal": "", "critical": false, "description": "", "display_type": ""}, - "write.total_uncorrected_errors": {"ideal": "low", "critical": true, "description": "", "display_type": ""} - }, "success": true + "write_total_errors_corrected": { + "ideal": "", + "critical": false, + "description": "", + "display_type": "" + }, + "write_total_uncorrected_errors": { + "ideal": "low", + "critical": true, + "description": "", + "display_type": "" + } + }, + "success": true } diff --git a/webapp/frontend/src/app/data/mock/summary/data.ts b/webapp/frontend/src/app/data/mock/summary/data.ts index 7c60702..70acf16 100644 --- a/webapp/frontend/src/app/data/mock/summary/data.ts +++ b/webapp/frontend/src/app/data/mock/summary/data.ts @@ -2,812 +2,597 @@ import * as moment from 'moment'; /* tslint:disable:max-line-length */ export const summary = { - "data": [{ - "CreatedAt": "2020-08-28T07:55:27.751071002Z", - "UpdatedAt": "2020-09-08T21:39:26.571901-07:00", - "DeletedAt": null, - "wwn": "0x5002538e40a22954", - "device_name": "sda", - "manufacturer": "ATA", - "model_name": "Samsung_SSD_860_EVO_500GB", - "interface_type": "SCSI", - "host_id": "NAS", - "interface_speed": "", - "serial_number": "S3YZNB0KBXXXXXX", - "firmware": "002C", - "rotational_speed": 0, - "capacity": 1024209543168, - "form_factor": "", - "smart_support": false, - "device_protocol": "NVMe", - "device_type": "nvme", - "smart_results": [{ - "ID": 46, - "CreatedAt": "2020-09-08T21:39:26.572596-07:00", - "UpdatedAt": "2020-09-08T21:39:26.572596-07:00", - "DeletedAt": null, - "device_wwn": "0x5002538e40a22954", - "date": "2020-06-10T05:01:02-07:00", - "smart_status": "passed", - "temp": 36, - "power_on_hours": 2401, - "power_cycle_count": 266, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 40, - "CreatedAt": "2020-09-07T15:47:21.336531606Z", - "UpdatedAt": "2020-09-07T15:47:21.336531606Z", - "DeletedAt": null, - "device_wwn": "0x5002538e40a22954", - "date": "2020-06-10T12:01:02Z", - "smart_status": "passed", - "temp": 36, - "power_on_hours": 2401, - "power_cycle_count": 266, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 34, - "CreatedAt": "2020-09-07T15:38:56.633173997Z", - "UpdatedAt": "2020-09-07T15:38:56.633173997Z", - "DeletedAt": null, - "device_wwn": "0x5002538e40a22954", - "date": "2020-06-10T12:01:02Z", - "smart_status": "passed", - "temp": 36, - "power_on_hours": 2401, - "power_cycle_count": 266, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 28, - "CreatedAt": "2020-09-07T15:26:07.504746443Z", - "UpdatedAt": "2020-09-07T15:26:07.504746443Z", - "DeletedAt": null, - "device_wwn": "0x5002538e40a22954", - "date": "2020-06-10T12:01:02Z", - "smart_status": "passed", - "temp": 36, - "power_on_hours": 2401, - "power_cycle_count": 266, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 22, - "CreatedAt": "2020-09-07T15:19:17.467677684Z", - "UpdatedAt": "2020-09-07T15:19:17.467677684Z", - "DeletedAt": null, - "device_wwn": "0x5002538e40a22954", - "date": "2020-06-10T12:01:02Z", - "smart_status": "passed", - "temp": 36, - "power_on_hours": 2401, - "power_cycle_count": 266, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 16, - "CreatedAt": "2020-09-07T15:10:40.245856096Z", - "UpdatedAt": "2020-09-07T15:10:40.245856096Z", - "DeletedAt": null, - "device_wwn": "0x5002538e40a22954", - "date": "2020-06-10T12:01:02Z", - "smart_status": "passed", - "temp": 36, - "power_on_hours": 2401, - "power_cycle_count": 266, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 10, - "CreatedAt": "2020-09-06T23:14:39.848993269Z", - "UpdatedAt": "2020-09-06T23:14:39.848993269Z", - "DeletedAt": null, - "device_wwn": "0x5002538e40a22954", - "date": "2020-06-10T12:01:02Z", - "smart_status": "passed", - "temp": 36, - "power_on_hours": 2401, - "power_cycle_count": 266, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 4, - "CreatedAt": "2020-08-28T07:55:27.833116549Z", - "UpdatedAt": "2020-08-28T07:55:27.833116549Z", - "DeletedAt": null, - "device_wwn": "0x5002538e40a22954", - "date": "2020-06-10T12:01:02Z", - "smart_status": "passed", - "temp": 36, - "power_on_hours": 2401, - "power_cycle_count": 266, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }] - }, { - "CreatedAt": "2020-08-28T07:55:27.755292213Z", - "UpdatedAt": "2020-09-08T21:39:26.56453-07:00", - "DeletedAt": null, - "wwn": "0x5000cca264eb01d7", - "device_name": "sdb", - "manufacturer": "ATA", - "model_name": "WDC_WD140EDFZ-11A0VA0", - "interface_type": "SCSI", - "interface_speed": "6.0 Gb/s", - "serial_number": "9RK1XXXXX", - "firmware": "81.00A81", - "rotational_speed": 5400, - "capacity": 14000519643136, - "form_factor": "3.5 inches", - "smart_support": false, - "device_protocol": "ATA", - "device_type": "sat", - "smart_results": [{ - "ID": 44, - "CreatedAt": "2020-09-08T21:39:26.565492-07:00", - "UpdatedAt": "2020-09-08T21:39:26.565492-07:00", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-20T17:03:30-07:00", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 43, - "CreatedAt": "2020-09-08T21:39:26.552765-07:00", - "UpdatedAt": "2020-09-08T21:39:26.552765-07:00", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-20T17:03:30-07:00", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 38, - "CreatedAt": "2020-09-07T15:47:21.319490869Z", - "UpdatedAt": "2020-09-07T15:47:21.319490869Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-21T00:03:30Z", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 37, - "CreatedAt": "2020-09-07T15:47:21.305997039Z", - "UpdatedAt": "2020-09-07T15:47:21.305997039Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-21T00:03:30Z", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 32, - "CreatedAt": "2020-09-07T15:38:56.621396993Z", - "UpdatedAt": "2020-09-07T15:38:56.621396993Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-21T00:03:30Z", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 31, - "CreatedAt": "2020-09-07T15:38:56.608679081Z", - "UpdatedAt": "2020-09-07T15:38:56.608679081Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-21T00:03:30Z", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 26, - "CreatedAt": "2020-09-07T15:26:07.49254641Z", - "UpdatedAt": "2020-09-07T15:26:07.49254641Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-21T00:03:30Z", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 25, - "CreatedAt": "2020-09-07T15:26:07.478522227Z", - "UpdatedAt": "2020-09-07T15:26:07.478522227Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-21T00:03:30Z", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 20, - "CreatedAt": "2020-09-07T15:19:17.454485628Z", - "UpdatedAt": "2020-09-07T15:19:17.454485628Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-21T00:03:30Z", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 19, - "CreatedAt": "2020-09-07T15:19:17.440345175Z", - "UpdatedAt": "2020-09-07T15:19:17.440345175Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-21T00:03:30Z", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 14, - "CreatedAt": "2020-09-07T15:10:40.23412631Z", - "UpdatedAt": "2020-09-07T15:10:40.23412631Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-21T00:03:30Z", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 13, - "CreatedAt": "2020-09-07T15:10:40.221593119Z", - "UpdatedAt": "2020-09-07T15:10:40.221593119Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-21T00:03:30Z", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 8, - "CreatedAt": "2020-09-06T23:14:39.838574957Z", - "UpdatedAt": "2020-09-06T23:14:39.838574957Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-21T00:03:30Z", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 7, - "CreatedAt": "2020-09-06T23:14:39.828127845Z", - "UpdatedAt": "2020-09-06T23:14:39.828127845Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-21T00:03:30Z", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 2, - "CreatedAt": "2020-08-28T07:55:27.810831029Z", - "UpdatedAt": "2020-08-28T07:55:27.810831029Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-21T00:03:30Z", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 1, - "CreatedAt": "2020-08-28T07:55:27.793332347Z", - "UpdatedAt": "2020-08-28T07:55:27.793332347Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264eb01d7", - "date": "2020-06-21T00:03:30Z", - "smart_status": "passed", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }] - }, { - "CreatedAt": "2020-08-28T07:55:27.75951336Z", - "UpdatedAt": "2020-09-08T21:39:26.568442-07:00", - "DeletedAt": null, - "wwn": "0x5000cca264ec3183", - "device_name": "sdc", - "manufacturer": "ATA", - "model_name": "WDC_WD140EDFZ-11A0VA0", - "interface_type": "SCSI", - "interface_speed": "1.5 Gb/s", - "host_id": "NAS", - "serial_number": "9RK4XXXXX", - "firmware": "MS1OA650", - "rotational_speed": 7200, - "capacity": 500107862016, - "form_factor": "3.5 inches", - "smart_support": false, - "device_protocol": "ATA", - "device_type": "usbjmicron", - "smart_results": [{ - "ID": 45, - "CreatedAt": "2020-09-08T21:39:26.569345-07:00", - "UpdatedAt": "2020-09-08T21:39:26.569345-07:00", - "DeletedAt": null, - "device_wwn": "0x5000cca264ec3183", - "date": "2020-07-08T06:48:23-07:00", - "smart_status": "failed", - "temp": 25, - "power_on_hours": 65592, - "power_cycle_count": 86, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 39, - "CreatedAt": "2020-09-07T15:47:21.330857794Z", - "UpdatedAt": "2020-09-07T15:47:21.330857794Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264ec3183", - "date": "2020-07-08T13:48:23Z", - "smart_status": "failed", - "temp": 25, - "power_on_hours": 65592, - "power_cycle_count": 86, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 33, - "CreatedAt": "2020-09-07T15:38:56.628048752Z", - "UpdatedAt": "2020-09-07T15:38:56.628048752Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264ec3183", - "date": "2020-07-08T13:48:23Z", - "smart_status": "failed", - "temp": 25, - "power_on_hours": 65592, - "power_cycle_count": 86, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 27, - "CreatedAt": "2020-09-07T15:26:07.499431098Z", - "UpdatedAt": "2020-09-07T15:26:07.499431098Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264ec3183", - "date": "2020-07-08T13:48:23Z", - "smart_status": "failed", - "temp": 25, - "power_on_hours": 65592, - "power_cycle_count": 86, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 21, - "CreatedAt": "2020-09-07T15:19:17.461752104Z", - "UpdatedAt": "2020-09-07T15:19:17.461752104Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264ec3183", - "date": "2020-07-08T13:48:23Z", - "smart_status": "failed", - "temp": 25, - "power_on_hours": 65592, - "power_cycle_count": 86, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 15, - "CreatedAt": "2020-09-07T15:10:40.241142961Z", - "UpdatedAt": "2020-09-07T15:10:40.241142961Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264ec3183", - "date": "2020-07-08T13:48:23Z", - "smart_status": "failed", - "temp": 25, - "power_on_hours": 65592, - "power_cycle_count": 86, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 9, - "CreatedAt": "2020-09-06T23:14:39.844036921Z", - "UpdatedAt": "2020-09-06T23:14:39.844036921Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264ec3183", - "date": "2020-07-08T13:48:23Z", - "smart_status": "failed", - "temp": 25, - "power_on_hours": 65592, - "power_cycle_count": 86, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 3, - "CreatedAt": "2020-08-28T07:55:27.822428858Z", - "UpdatedAt": "2020-08-28T07:55:27.822428858Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264ec3183", - "date": "2020-07-08T13:48:23Z", - "smart_status": "failed", - "temp": 25, - "power_on_hours": 65592, - "power_cycle_count": 86, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }] - }, { - "CreatedAt": "2020-08-28T07:55:27.76380029Z", - "UpdatedAt": "2020-09-08T21:39:26.575283-07:00", - "DeletedAt": null, - "wwn": "0x5000cca252c859cc", - "device_name": "sdd", - "manufacturer": "SEAGATE", - "model_name": "WDC_WD80EFAX-68LHPN0", - "interface_type": "SCSI", - "interface_speed": "", - "serial_number": "7SGLXXXXX", - "firmware": "", - "rotational_speed": 7200, - "capacity": 4000787030016, - "form_factor": "3.5 inches", - "smart_support": false, - "device_protocol": "SCSI", - "device_type": "scsi", - "smart_results": [{ - "ID": 47, - "CreatedAt": "2020-09-08T21:39:26.576373-07:00", - "UpdatedAt": "2020-09-08T21:39:26.576373-07:00", - "DeletedAt": null, - "device_wwn": "0x5000cca252c859cc", - "date": "2020-08-21T15:27:02-07:00", - "smart_status": "passed", - "temp": 34, - "power_on_hours": 43549, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 41, - "CreatedAt": "2020-09-07T15:47:21.342459019Z", - "UpdatedAt": "2020-09-07T15:47:21.342459019Z", - "DeletedAt": null, - "device_wwn": "0x5000cca252c859cc", - "date": "2020-08-21T22:27:02Z", - "smart_status": "passed", - "temp": 34, - "power_on_hours": 43549, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 35, - "CreatedAt": "2020-09-07T15:38:56.637866738Z", - "UpdatedAt": "2020-09-07T15:38:56.637866738Z", - "DeletedAt": null, - "device_wwn": "0x5000cca252c859cc", - "date": "2020-08-21T22:27:02Z", - "smart_status": "passed", - "temp": 34, - "power_on_hours": 43549, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 29, - "CreatedAt": "2020-09-07T15:26:07.511074415Z", - "UpdatedAt": "2020-09-07T15:26:07.511074415Z", - "DeletedAt": null, - "device_wwn": "0x5000cca252c859cc", - "date": "2020-08-21T22:27:02Z", - "smart_status": "passed", - "temp": 34, - "power_on_hours": 43549, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 23, - "CreatedAt": "2020-09-07T15:19:17.472358868Z", - "UpdatedAt": "2020-09-07T15:19:17.472358868Z", - "DeletedAt": null, - "device_wwn": "0x5000cca252c859cc", - "date": "2020-08-21T22:27:02Z", - "smart_status": "passed", - "temp": 34, - "power_on_hours": 43549, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 17, - "CreatedAt": "2020-09-07T15:10:40.251846539Z", - "UpdatedAt": "2020-09-07T15:10:40.251846539Z", - "DeletedAt": null, - "device_wwn": "0x5000cca252c859cc", - "date": "2020-08-21T22:27:02Z", - "smart_status": "passed", - "temp": 34, - "power_on_hours": 43549, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 11, - "CreatedAt": "2020-09-06T23:14:39.854284927Z", - "UpdatedAt": "2020-09-06T23:14:39.854284927Z", - "DeletedAt": null, - "device_wwn": "0x5000cca252c859cc", - "date": "2020-08-21T22:27:02Z", - "smart_status": "passed", - "temp": 34, - "power_on_hours": 43549, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 5, - "CreatedAt": "2020-08-28T07:55:27.844861303Z", - "UpdatedAt": "2020-08-28T07:55:27.844861303Z", - "DeletedAt": null, - "device_wwn": "0x5000cca252c859cc", - "date": "2020-08-21T22:27:02Z", - "smart_status": "passed", - "temp": 34, - "power_on_hours": 43549, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }] - }, { - "CreatedAt": "2020-08-28T07:55:27.768220079Z", - "UpdatedAt": "2020-09-08T21:39:26.578973-07:00", - "DeletedAt": null, - "wwn": "0x5000cca264ebc248", - "device_name": "sde", - "manufacturer": "SEAGATE", - "model_name": "WDC_WD140EDFZ-11A0VA0", - "interface_type": "SCSI", - "interface_speed": "", - "serial_number": "9RK3XXXXX", - "firmware": "", - "rotational_speed": 10500, - "capacity": 1200243695616, - "form_factor": "2.5 inches", - "smart_support": false, - "device_protocol": "SCSI", - "device_type": "scsi", - "smart_results": [{ - "ID": 48, - "CreatedAt": "2020-09-08T21:39:26.579623-07:00", - "UpdatedAt": "2020-09-08T21:39:26.579623-07:00", - "DeletedAt": null, - "device_wwn": "0x5000cca264ebc248", - "date": "2018-12-16T15:09:15-08:00", - "smart_status": "passed", - "temp": 31, - "power_on_hours": 5675, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 42, - "CreatedAt": "2020-09-07T15:47:21.347776031Z", - "UpdatedAt": "2020-09-07T15:47:21.347776031Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264ebc248", - "date": "2018-12-16T23:09:15Z", - "smart_status": "passed", - "temp": 31, - "power_on_hours": 5675, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 36, - "CreatedAt": "2020-09-07T15:38:56.643057784Z", - "UpdatedAt": "2020-09-07T15:38:56.643057784Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264ebc248", - "date": "2018-12-16T23:09:15Z", - "smart_status": "passed", - "temp": 31, - "power_on_hours": 5675, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 30, - "CreatedAt": "2020-09-07T15:26:07.517198383Z", - "UpdatedAt": "2020-09-07T15:26:07.517198383Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264ebc248", - "date": "2018-12-16T23:09:15Z", - "smart_status": "passed", - "temp": 31, - "power_on_hours": 5675, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 24, - "CreatedAt": "2020-09-07T15:19:17.478179249Z", - "UpdatedAt": "2020-09-07T15:19:17.478179249Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264ebc248", - "date": "2018-12-16T23:09:15Z", - "smart_status": "passed", - "temp": 31, - "power_on_hours": 5675, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 18, - "CreatedAt": "2020-09-07T15:10:40.257160678Z", - "UpdatedAt": "2020-09-07T15:10:40.257160678Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264ebc248", - "date": "2018-12-16T23:09:15Z", - "smart_status": "passed", - "temp": 31, - "power_on_hours": 5675, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 12, - "CreatedAt": "2020-09-06T23:14:39.858637958Z", - "UpdatedAt": "2020-09-06T23:14:39.858637958Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264ebc248", - "date": "2018-12-16T23:09:15Z", - "smart_status": "passed", - "temp": 31, - "power_on_hours": 5675, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }, { - "ID": 6, - "CreatedAt": "2020-08-28T07:55:27.879998203Z", - "UpdatedAt": "2020-08-28T07:55:27.879998203Z", - "DeletedAt": null, - "device_wwn": "0x5000cca264ebc248", - "date": "2018-12-16T23:09:15Z", - "smart_status": "passed", - "temp": 31, - "power_on_hours": 5675, - "power_cycle_count": 0, - "ata_attributes": null, - "nvme_attributes": null, - "scsi_attributes": null - }] - }, { - "CreatedAt": "2020-08-28T07:55:27.772557223Z", - "UpdatedAt": "2020-08-28T07:55:27.772557223Z", - "DeletedAt": null, - "wwn": "0x50014ee20b2a72a9", - "device_name": "sdf", - "manufacturer": "ATA", - "model_name": "WDC_WD60EFRX-68MYMN1", - "interface_type": "SCSI", - "interface_speed": "", - "serial_number": "WD-WXL1HXXXXX", - "firmware": "", - "rotational_speed": 0, - "capacity": 6001175126016, - "form_factor": "", - "smart_support": false, - "device_protocol": "", - "device_type": "", - "smart_results": [] - }, { - "CreatedAt": "2020-08-28T07:55:27.776820757Z", - "UpdatedAt": "2020-08-28T07:55:27.776820757Z", - "DeletedAt": null, - "wwn": "0x5000c500673e6b5f", - "device_name": "sdg", - "manufacturer": "ATA", - "model_name": "ST6000DX000-1H217Z", - "interface_type": "SCSI", - "interface_speed": "", - "serial_number": "Z4DXXXXX", - "firmware": "", - "rotational_speed": 0, - "capacity": 6001175126016, - "form_factor": "", - "smart_support": false, - "device_protocol": "", - "device_type": "", - "smart_results": [] - }], "success": true -}; + "data": { + "summary": { + "0x5000c500673e6b5f": { + "device": { + "CreatedAt": "2021-04-30T08:17:13.155217-07:00", + "UpdatedAt": "2021-04-30T08:17:13.155217-07:00", + "DeletedAt": null, + "wwn": "0x5000c500673e6b5f", + "device_name": "sdg", + "manufacturer": "ATA", + "model_name": "ST6000DX000-1H217Z", + "interface_type": "SCSI", + "interface_speed": "", + "serial_number": "Z4DXXXXX", + "firmware": "", + "rotational_speed": 0, + "capacity": 6001175126016, + "form_factor": "", + "smart_support": false, + "device_protocol": "", + "device_type": "", + "label": "", + "host_id": "", + "device_status": 0 + } + }, + "0x5000cca252c859cc": { + "device": { + "CreatedAt": "2021-04-30T08:17:13.152705-07:00", + "UpdatedAt": "2021-05-02T14:22:50.357164-07:00", + "DeletedAt": null, + "wwn": "0x5000cca252c859cc", + "device_name": "sdd", + "manufacturer": "ATA", + "model_name": "WDC_WD80EFAX-68LHPN0", + "interface_type": "SCSI", + "interface_speed": "", + "serial_number": "7SGLXXXXX", + "firmware": "", + "rotational_speed": 0, + "capacity": 8001563222016, + "form_factor": "", + "smart_support": false, + "device_protocol": "", + "device_type": "", + "label": "", + "host_id": "", + "device_status": 0 + }, + "smart": { + "collector_date": "2020-08-21T22:27:02Z", + "temp": 34, + "power_on_hours": 43549 + }, + "temp_history": [{ + "date": "2020-08-21T22:27:02Z", + "temp": 34 + }] + }, + "0x5000cca264eb01d7": { + "device": { + "CreatedAt": "2021-04-28T20:52:49.047154-07:00", + "UpdatedAt": "2021-05-02T14:22:49.86136-07:00", + "DeletedAt": null, + "wwn": "0x5000cca264eb01d7", + "device_name": "sdb", + "manufacturer": "ATA", + "model_name": "WDC_WD140EDFZ-11A0VA0", + "interface_type": "SCSI", + "interface_speed": "", + "serial_number": "9RK1XXXXX", + "firmware": "81.00A81", + "rotational_speed": 0, + "capacity": 14000519643136, + "form_factor": "", + "smart_support": false, + "device_protocol": "", + "device_type": "", + "label": "", + "host_id": "", + "device_status": 0 + }, + "smart": { + "collector_date": "2020-06-21T00:03:30Z", + "temp": 32, + "power_on_hours": 1730 + }, + "temp_history": [{ + "date": "2020-06-21T00:03:30Z", + "temp": 32 + }] + }, + "0x5000cca264ebc248": { + "device": { + "CreatedAt": "2021-04-30T08:17:13.153782-07:00", + "UpdatedAt": "2021-05-02T14:22:50.385282-07:00", + "DeletedAt": null, + "wwn": "0x5000cca264ebc248", + "device_name": "sde", + "manufacturer": "ATA", + "model_name": "WDC_WD140EDFZ-11A0VA0", + "interface_type": "SCSI", + "interface_speed": "", + "serial_number": "9RK3XXXXX", + "firmware": "", + "rotational_speed": 0, + "capacity": 14000519643136, + "form_factor": "", + "smart_support": false, + "device_protocol": "", + "device_type": "", + "label": "", + "host_id": "", + "device_status": 0 + } + }, + "0x5000cca264ec3183": { + "device": { + "CreatedAt": "2021-04-30T08:17:13.151906-07:00", + "UpdatedAt": "2021-05-02T14:49:51.645012-07:00", + "DeletedAt": null, + "wwn": "0x5000cca264ec3183", + "device_name": "sdc", + "manufacturer": "ATA", + "model_name": "WDC_WD140EDFZ-11A0VA0", + "interface_type": "SCSI", + "interface_speed": "", + "serial_number": "9RK4XXXXX", + "firmware": "RVT02B6Q", + "rotational_speed": 0, + "capacity": 14000519643136, + "form_factor": "", + "smart_support": false, + "device_protocol": "", + "device_type": "", + "label": "", + "host_id": "", + "device_status": 1 + }, + "smart": { + "collector_date": "2020-09-13T16:29:23Z", + "temp": 36, + "power_on_hours": 14551 + }, + "temp_history": [{ + "date": "2020-07-08T13:48:23Z", + "temp": 25 + }, { + "date": "2020-09-12T19:19:23Z", + "temp": 37 + }, { + "date": "2020-09-12T19:29:23Z", + "temp": 37 + }, { + "date": "2020-09-12T19:39:23Z", + "temp": 36 + }, { + "date": "2020-09-12T19:49:23Z", + "temp": 36 + }, { + "date": "2020-09-12T19:59:23Z", + "temp": 37 + }, { + "date": "2020-09-12T20:09:23Z", + "temp": 37 + }, { + "date": "2020-09-12T20:19:23Z", + "temp": 37 + }, { + "date": "2020-09-12T20:29:23Z", + "temp": 37 + }, { + "date": "2020-09-12T20:39:23Z", + "temp": 36 + }, { + "date": "2020-09-12T20:49:23Z", + "temp": 36 + }, { + "date": "2020-09-12T20:59:23Z", + "temp": 37 + }, { + "date": "2020-09-12T21:09:23Z", + "temp": 36 + }, { + "date": "2020-09-12T21:19:23Z", + "temp": 37 + }, { + "date": "2020-09-12T21:29:23Z", + "temp": 38 + }, { + "date": "2020-09-12T21:39:23Z", + "temp": 36 + }, { + "date": "2020-09-12T21:49:23Z", + "temp": 36 + }, { + "date": "2020-09-12T21:59:23Z", + "temp": 36 + }, { + "date": "2020-09-12T22:09:23Z", + "temp": 36 + }, { + "date": "2020-09-12T22:19:23Z", + "temp": 36 + }, { + "date": "2020-09-12T22:29:23Z", + "temp": 36 + }, { + "date": "2020-09-12T22:39:23Z", + "temp": 36 + }, { + "date": "2020-09-12T22:49:23Z", + "temp": 36 + }, { + "date": "2020-09-12T22:59:23Z", + "temp": 36 + }, { + "date": "2020-09-12T23:09:23Z", + "temp": 36 + }, { + "date": "2020-09-12T23:19:23Z", + "temp": 36 + }, { + "date": "2020-09-12T23:29:23Z", + "temp": 36 + }, { + "date": "2020-09-12T23:39:23Z", + "temp": 36 + }, { + "date": "2020-09-12T23:49:23Z", + "temp": 36 + }, { + "date": "2020-09-12T23:59:23Z", + "temp": 36 + }, { + "date": "2020-09-13T00:09:23Z", + "temp": 36 + }, { + "date": "2020-09-13T00:19:23Z", + "temp": 36 + }, { + "date": "2020-09-13T00:29:23Z", + "temp": 37 + }, { + "date": "2020-09-13T00:39:23Z", + "temp": 36 + }, { + "date": "2020-09-13T00:49:23Z", + "temp": 36 + }, { + "date": "2020-09-13T00:59:23Z", + "temp": 36 + }, { + "date": "2020-09-13T01:09:23Z", + "temp": 36 + }, { + "date": "2020-09-13T01:19:23Z", + "temp": 36 + }, { + "date": "2020-09-13T01:29:23Z", + "temp": 37 + }, { + "date": "2020-09-13T01:39:23Z", + "temp": 36 + }, { + "date": "2020-09-13T01:49:23Z", + "temp": 37 + }, { + "date": "2020-09-13T01:59:23Z", + "temp": 37 + }, { + "date": "2020-09-13T02:09:23Z", + "temp": 37 + }, { + "date": "2020-09-13T02:19:23Z", + "temp": 37 + }, { + "date": "2020-09-13T02:29:23Z", + "temp": 38 + }, { + "date": "2020-09-13T02:39:23Z", + "temp": 37 + }, { + "date": "2020-09-13T02:49:23Z", + "temp": 37 + }, { + "date": "2020-09-13T02:59:23Z", + "temp": 38 + }, { + "date": "2020-09-13T03:09:23Z", + "temp": 38 + }, { + "date": "2020-09-13T03:19:23Z", + "temp": 38 + }, { + "date": "2020-09-13T03:29:23Z", + "temp": 38 + }, { + "date": "2020-09-13T03:39:23Z", + "temp": 38 + }, { + "date": "2020-09-13T03:49:23Z", + "temp": 38 + }, { + "date": "2020-09-13T03:59:23Z", + "temp": 38 + }, { + "date": "2020-09-13T04:09:23Z", + "temp": 38 + }, { + "date": "2020-09-13T04:19:23Z", + "temp": 38 + }, { + "date": "2020-09-13T04:29:23Z", + "temp": 38 + }, { + "date": "2020-09-13T04:39:23Z", + "temp": 38 + }, { + "date": "2020-09-13T04:49:23Z", + "temp": 38 + }, { + "date": "2020-09-13T04:59:23Z", + "temp": 38 + }, { + "date": "2020-09-13T05:09:23Z", + "temp": 37 + }, { + "date": "2020-09-13T05:19:23Z", + "temp": 38 + }, { + "date": "2020-09-13T05:29:23Z", + "temp": 39 + }, { + "date": "2020-09-13T05:39:23Z", + "temp": 41 + }, { + "date": "2020-09-13T05:49:23Z", + "temp": 42 + }, { + "date": "2020-09-13T05:59:23Z", + "temp": 41 + }, { + "date": "2020-09-13T06:09:23Z", + "temp": 41 + }, { + "date": "2020-09-13T06:19:23Z", + "temp": 42 + }, { + "date": "2020-09-13T06:29:23Z", + "temp": 41 + }, { + "date": "2020-09-13T06:39:23Z", + "temp": 41 + }, { + "date": "2020-09-13T06:49:23Z", + "temp": 41 + }, { + "date": "2020-09-13T06:59:23Z", + "temp": 41 + }, { + "date": "2020-09-13T07:09:23Z", + "temp": 40 + }, { + "date": "2020-09-13T07:19:23Z", + "temp": 40 + }, { + "date": "2020-09-13T07:29:23Z", + "temp": 41 + }, { + "date": "2020-09-13T07:39:23Z", + "temp": 43 + }, { + "date": "2020-09-13T07:49:23Z", + "temp": 42 + }, { + "date": "2020-09-13T07:59:23Z", + "temp": 41 + }, { + "date": "2020-09-13T08:09:23Z", + "temp": 42 + }, { + "date": "2020-09-13T08:19:23Z", + "temp": 42 + }, { + "date": "2020-09-13T08:29:23Z", + "temp": 41 + }, { + "date": "2020-09-13T08:39:23Z", + "temp": 39 + }, { + "date": "2020-09-13T08:49:23Z", + "temp": 38 + }, { + "date": "2020-09-13T08:59:23Z", + "temp": 38 + }, { + "date": "2020-09-13T09:09:23Z", + "temp": 38 + }, { + "date": "2020-09-13T09:19:23Z", + "temp": 39 + }, { + "date": "2020-09-13T09:29:23Z", + "temp": 39 + }, { + "date": "2020-09-13T09:39:23Z", + "temp": 39 + }, { + "date": "2020-09-13T09:49:23Z", + "temp": 39 + }, { + "date": "2020-09-13T09:59:23Z", + "temp": 39 + }, { + "date": "2020-09-13T10:09:23Z", + "temp": 39 + }, { + "date": "2020-09-13T10:19:23Z", + "temp": 39 + }, { + "date": "2020-09-13T10:29:23Z", + "temp": 39 + }, { + "date": "2020-09-13T10:39:23Z", + "temp": 39 + }, { + "date": "2020-09-13T10:49:23Z", + "temp": 39 + }, { + "date": "2020-09-13T10:59:23Z", + "temp": 39 + }, { + "date": "2020-09-13T11:09:23Z", + "temp": 38 + }, { + "date": "2020-09-13T11:19:23Z", + "temp": 38 + }, { + "date": "2020-09-13T11:29:23Z", + "temp": 38 + }, { + "date": "2020-09-13T11:39:23Z", + "temp": 38 + }, { + "date": "2020-09-13T11:49:23Z", + "temp": 38 + }, { + "date": "2020-09-13T11:59:23Z", + "temp": 38 + }, { + "date": "2020-09-13T12:09:23Z", + "temp": 38 + }, { + "date": "2020-09-13T12:19:23Z", + "temp": 38 + }, { + "date": "2020-09-13T12:29:23Z", + "temp": 39 + }, { + "date": "2020-09-13T12:39:23Z", + "temp": 39 + }, { + "date": "2020-09-13T12:49:23Z", + "temp": 39 + }, { + "date": "2020-09-13T12:59:23Z", + "temp": 39 + }, { + "date": "2020-09-13T13:09:23Z", + "temp": 39 + }, { + "date": "2020-09-13T13:19:23Z", + "temp": 39 + }, { + "date": "2020-09-13T13:29:23Z", + "temp": 39 + }, { + "date": "2020-09-13T13:39:23Z", + "temp": 39 + }, { + "date": "2020-09-13T13:49:23Z", + "temp": 39 + }, { + "date": "2020-09-13T13:59:23Z", + "temp": 39 + }, { + "date": "2020-09-13T14:09:23Z", + "temp": 39 + }, { + "date": "2020-09-13T14:19:23Z", + "temp": 39 + }, { + "date": "2020-09-13T14:29:23Z", + "temp": 39 + }, { + "date": "2020-09-13T14:39:23Z", + "temp": 39 + }, { + "date": "2020-09-13T14:49:23Z", + "temp": 39 + }, { + "date": "2020-09-13T14:59:23Z", + "temp": 39 + }, { + "date": "2020-09-13T15:09:23Z", + "temp": 39 + }, { + "date": "2020-09-13T15:19:23Z", + "temp": 40 + }, { + "date": "2020-09-13T15:29:23Z", + "temp": 40 + }, { + "date": "2020-09-13T15:39:23Z", + "temp": 40 + }, { + "date": "2020-09-13T15:49:23Z", + "temp": 39 + }, { + "date": "2020-09-13T15:59:23Z", + "temp": 39 + }, { + "date": "2020-09-13T16:09:23Z", + "temp": 39 + }, { + "date": "2020-09-13T16:19:23Z", + "temp": 39 + }, { + "date": "2020-09-13T16:29:23Z", + "temp": 39 + }] + }, + "0x50014ee20b2a72a9": { + "device": { + "CreatedAt": "2021-04-30T08:17:13.15451-07:00", + "UpdatedAt": "2021-04-30T08:17:13.15451-07:00", + "DeletedAt": null, + "wwn": "0x50014ee20b2a72a9", + "device_name": "sdf", + "manufacturer": "ATA", + "model_name": "WDC_WD60EFRX-68MYMN1", + "interface_type": "SCSI", + "interface_speed": "", + "serial_number": "WD-WXL1HXXXXX", + "firmware": "", + "rotational_speed": 0, + "capacity": 6001175126016, + "form_factor": "", + "smart_support": false, + "device_protocol": "", + "device_type": "", + "label": "", + "host_id": "", + "device_status": 0 + } + }, + "0x5002538e40a22954": { + "device": { + "CreatedAt": "2021-04-30T08:17:13.150792-07:00", + "UpdatedAt": "2021-05-02T14:22:50.330706-07:00", + "DeletedAt": null, + "wwn": "0x5002538e40a22954", + "device_name": "sda", + "manufacturer": "ATA", + "model_name": "Samsung_SSD_860_EVO_500GB", + "interface_type": "SCSI", + "interface_speed": "", + "serial_number": "S3YZNB0KBXXXXXX", + "firmware": "002C", + "rotational_speed": 0, + "capacity": 500107862016, + "form_factor": "", + "smart_support": false, + "device_protocol": "", + "device_type": "", + "label": "", + "host_id": "", + "device_status": 0 + }, + "smart": { + "collector_date": "2020-06-10T12:01:02Z", + "temp": 36, + "power_on_hours": 2401 + }, + "temp_history": [{ + "date": "2020-06-10T12:01:02Z", + "temp": 36 + }] + } + } + }, + "success": true +} diff --git a/webapp/frontend/src/app/modules/dashboard/dashboard.component.html b/webapp/frontend/src/app/modules/dashboard/dashboard.component.html index 82a723f..4fd1574 100644 --- a/webapp/frontend/src/app/modules/dashboard/dashboard.component.html +++ b/webapp/frontend/src/app/modules/dashboard/dashboard.component.html @@ -1,4 +1,5 @@ -
+ +
@@ -47,38 +48,37 @@
- -
-
+
- {{deviceTitle(disk)}} -
- Last Updated on {{disk.smart_results[0]?.date | date:'MMMM dd, yyyy - HH:mm' }} + {{deviceTitle(summary.value.device)}} +
+ Last Updated on {{summary.value.smart.collector_date | date:'MMMM dd, yyyy - HH:mm' }}
-
-
-
/dev/{{data.data.device_name}}
+
/dev/{{device?.device_name}}
-
-
{{data.data.host_id}}
+
+
{{device?.host_id}}
Host ID
-
-
{{data.data.device_type | uppercase}}
+
+
{{device?.device_type | uppercase}}
Device Type
-
-
{{data.data.manufacturer}}
+
+
{{device?.manufacturer}}
Model Family
-
{{data.data.model_name}}
+
{{device?.model_name}}
Device Model
-
{{data.data.serial_number}}
+
{{device?.serial_number}}
Serial Number
-
{{data.data.wwn}}
+
{{device?.wwn}}
LU WWN Device Id
-
{{data.data.firmware}}
+
{{device?.firmware}}
Firmware Version
-
{{data.data.capacity | fileSize}}
+
{{device?.capacity | fileSize}}
Capacity
-
-
{{data.data.rotational_speed}} RPM
+
+
{{device?.rotational_speed}} RPM
Rotation Rate
-
-
{{data.data.device_protocol}}
+
+
{{device?.device_protocol}}
Protocol
-
{{data.data.smart_results[0]?.power_cycle_count}}
+
{{smart_results[0]?.power_cycle_count}}
Power Cycle Count
-
-
{{humanizeDuration(data.data.smart_results[0]?.power_on_hours *60 * 60 * 1000, { round: true, largest: 1, units: ['y', 'd', 'h'] })}}
+
+
{{humanizeDuration(smart_results[0]?.power_on_hours *60 * 60 * 1000, { round: true, largest: 1, units: ['y', 'd', 'h'] })}}
Powered On
-
{{data.data.smart_results[0]?.temp}}°C
+
{{smart_results[0]?.temp}}°C
Temperature
@@ -115,7 +115,7 @@
-
S.M.A.R.T {{data.data.device_protocol}} Attributes
+
S.M.A.R.T {{device?.device_protocol}} Attributes
{{this.smartAttributeDataSource.data.length}} visible, {{getHiddenAttributes()}} hidden
diff --git a/webapp/frontend/src/app/modules/detail/detail.component.ts b/webapp/frontend/src/app/modules/detail/detail.component.ts index a4321ec..eaf5b7c 100644 --- a/webapp/frontend/src/app/modules/detail/detail.component.ts +++ b/webapp/frontend/src/app/modules/detail/detail.component.ts @@ -19,7 +19,12 @@ import humanizeDuration from 'humanize-duration'; export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { onlyCritical: boolean = true; - data: any; + // data: any; + + metadata: any; + device: any; + smart_results: any[]; + commonSparklineOptions: Partial; smartAttributeDataSource: MatTableDataSource; smartAttributeTableColumns: string[]; @@ -66,10 +71,14 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { .subscribe((data) => { // Store the data - this.data = data; + // this.data = data; + this.device = data.data.device; + this.smart_results = data.data.smart_results + this.metadata = data.metadata; + // Store the table data - this.smartAttributeDataSource.data = this._generateSmartAttributeTableDataSource(data.data.smart_results); + this.smartAttributeDataSource.data = this._generateSmartAttributeTableDataSource(this.smart_results); // Prepare the chart data this._prepareChartData(); @@ -99,7 +108,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { // @ Private methods // ----------------------------------------------------------------------------------------------------- getAttributeDescription(attribute_data){ - let attribute_metadata = this.data.metadata[attribute_data.attribute_id] + let attribute_metadata = this.metadata[attribute_data.attribute_id] if(!attribute_metadata){ return 'Unknown' } else { @@ -110,7 +119,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { getAttributeValue(attribute_data){ if(this.isAta()) { - let attribute_metadata = this.data.metadata[attribute_data.attribute_id] + let attribute_metadata = this.metadata[attribute_data.attribute_id] if(!attribute_metadata){ return attribute_data.value } else if (attribute_metadata.display_type == "raw") { @@ -128,7 +137,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { getAttributeValueType(attribute_data){ if(this.isAta()) { - let attribute_metadata = this.data.metadata[attribute_data.attribute_id] + let attribute_metadata = this.metadata[attribute_data.attribute_id] if(!attribute_metadata){ return '' } else { @@ -141,14 +150,14 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { getAttributeIdeal(attribute_data){ if(this.isAta()){ - return this.data.metadata[attribute_data.attribute_id]?.display_type == "raw" ? this.data.metadata[attribute_data.attribute_id]?.ideal : '' + return this.metadata[attribute_data.attribute_id]?.display_type == "raw" ? this.metadata[attribute_data.attribute_id]?.ideal : '' } else { - return this.data.metadata[attribute_data.attribute_id]?.ideal + return this.metadata[attribute_data.attribute_id]?.ideal } } getAttributeWorst(attribute_data){ - let attribute_metadata = this.data.metadata[attribute_data.attribute_id] + let attribute_metadata = this.metadata[attribute_data.attribute_id] if(!attribute_metadata){ return attribute_data.worst } else { @@ -158,7 +167,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { getAttributeThreshold(attribute_data){ if(this.isAta()){ - let attribute_metadata = this.data.metadata[attribute_data.attribute_id] + let attribute_metadata = this.metadata[attribute_data.attribute_id] if(!attribute_metadata || attribute_metadata.display_type == "normalized"){ return attribute_data.thresh } else { @@ -175,29 +184,30 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { } getAttributeCritical(attribute_data){ - return this.data.metadata[attribute_data.attribute_id]?.critical + return this.metadata[attribute_data.attribute_id]?.critical } getHiddenAttributes(){ - let attributes_list - if(this.isAta()){ - attributes_list = this.data.data.smart_results[0]?.ata_attributes - } else if(this.isNvme()){ - attributes_list = this.data.data.smart_results[0]?.nvme_attributes - } else { - attributes_list = this.data.data.smart_results[0]?.scsi_attributes + if (!this.smart_results || this.smart_results.length == 0) { + return 0 + } + + let attributes_length = 0 + let attributes = this.smart_results[0]?.attrs + if (attributes) { + attributes_length = Object.keys(attributes).length } - return attributes_list.length - this.smartAttributeDataSource.data.length + return attributes_length - this.smartAttributeDataSource.data.length } isAta(): boolean { - return this.data.data.device_protocol == 'ATA' + return this.device.device_protocol == 'ATA' } isScsi(): boolean { - return this.data.data.device_protocol == 'SCSI' + return this.device.device_protocol == 'SCSI' } isNvme(): boolean { - return this.data.data.device_protocol == 'NVMe' + return this.device.device_protocol == 'NVMe' } private _generateSmartAttributeTableDataSource(smart_results){ @@ -207,21 +217,22 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { return smartAttributeDataSource } var latest_smart_result = smart_results[0]; - let attributes_list = [] + let attributes = {} if(this.isScsi()) { this.smartAttributeTableColumns = ['status', 'name', 'value', 'thresh', 'history']; - attributes_list = latest_smart_result.scsi_attributes + attributes = latest_smart_result.attrs } else if(this.isNvme()){ this.smartAttributeTableColumns = ['status', 'name', 'value', 'thresh', 'ideal', 'history']; - attributes_list = latest_smart_result.nvme_attributes + attributes = latest_smart_result.attrs } else { //ATA - attributes_list = latest_smart_result.ata_attributes + attributes = latest_smart_result.attrs this.smartAttributeTableColumns = ['status', 'id', 'name', 'value', 'worst', 'thresh','ideal', 'failure', 'history']; } + for(const attrId in attributes){ + var attr = attributes[attrId] - for(let attr of attributes_list){ //chart history data if (!attr.chartData) { var rawHistory = (attr.history || []).map(hist_attr => this.getAttributeValue(hist_attr)).reverse() @@ -235,7 +246,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { } //determine when to include the attributes in table. - if(!this.onlyCritical || this.onlyCritical && this.data.metadata[attr.attribute_id]?.critical || attr.value < attr.thresh){ + if(!this.onlyCritical || this.onlyCritical && this.metadata[attr.attribute_id]?.critical || attr.value < attr.thresh){ smartAttributeDataSource.push(attr) } } @@ -297,7 +308,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { } toggleOnlyCritical(){ this.onlyCritical = !this.onlyCritical - this.smartAttributeDataSource.data = this._generateSmartAttributeTableDataSource(this.data.data.smart_results); + this.smartAttributeDataSource.data = this._generateSmartAttributeTableDataSource(this.smart_results); } From 694fc74ca0264cda42723d90f4d5169e1b4a8c68 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 27 Jun 2021 13:44:01 -0700 Subject: [PATCH 002/114] fixing history. --- .../src/app/modules/detail/detail.component.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/webapp/frontend/src/app/modules/detail/detail.component.ts b/webapp/frontend/src/app/modules/detail/detail.component.ts index eaf5b7c..df396b6 100644 --- a/webapp/frontend/src/app/modules/detail/detail.component.ts +++ b/webapp/frontend/src/app/modules/detail/detail.component.ts @@ -235,12 +235,20 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { //chart history data if (!attr.chartData) { - var rawHistory = (attr.history || []).map(hist_attr => this.getAttributeValue(hist_attr)).reverse() - rawHistory.push(this.getAttributeValue(attr)) - attr.chartData = [ + + + var attrHistory = [] + for (let smart_result of smart_results){ + attrHistory.push(this.getAttributeValue(smart_result.attrs[attrId])) + } + + // var rawHistory = (attr.history || []).map(hist_attr => this.getAttributeValue(hist_attr)).reverse() + // rawHistory.push(this.getAttributeValue(attr)) + + attributes[attrId].chartData = [ { name: "chart-line-sparkline", - data: rawHistory + data: attrHistory } ] } From 5c614c5512feaab71ff06a2de8cc9c17d68942cc Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 25 Jul 2021 14:51:28 -0700 Subject: [PATCH 003/114] adding docker build -> ghcr.io --- .github/workflows/docker-build.yaml | 53 +++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/workflows/docker-build.yaml diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml new file mode 100644 index 0000000..337b6c8 --- /dev/null +++ b/.github/workflows/docker-build.yaml @@ -0,0 +1,53 @@ +name: Docker +on: + schedule: + - cron: '36 12 * * *' + push: + branches: [ master, influxdb ] + # Publish semver tags as releases. + tags: [ 'v*.*.*' ] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} From ef014150a546441e83504d7ad330ee2433b25cf4 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 25 Jul 2021 15:39:30 -0700 Subject: [PATCH 004/114] tagging. --- .github/workflows/docker-build.yaml | 82 ++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml index 337b6c8..a7c1685 100644 --- a/.github/workflows/docker-build.yaml +++ b/.github/workflows/docker-build.yaml @@ -13,8 +13,7 @@ env: jobs: - build: - + collector: runs-on: ubuntu-latest permissions: contents: read @@ -23,7 +22,45 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + tags: | + type=ref,enable=true,event=branch,prefix=collector- + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + file: docker/Dockerfile.collector + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + web: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v2 # Login against a Docker registry except on PR # https://github.com/docker/login-action - name: Log into registry ${{ env.REGISTRY }} @@ -33,13 +70,53 @@ jobs: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + tags: | + type=ref,enable=true,event=branch,prefix=web- + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + file: docker/Dockerfile.web + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + omnibus: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} # Extract metadata (tags, labels) for Docker # https://github.com/docker/metadata-action - name: Extract Docker metadata id: meta uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 with: + tags: | + type=ref,enable=true,event=branch,prefix=omnibus- images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # Build and push Docker image with Buildx (don't push on PR) @@ -48,6 +125,7 @@ jobs: uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc with: context: . + file: docker/Dockerfile push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From 967a927e2d3165f5a64a41ff67cef0deed56b9bc Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 25 Jul 2021 15:52:07 -0700 Subject: [PATCH 005/114] setting the image type as suffix. --- .github/workflows/docker-build.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml index a7c1685..aa03a25 100644 --- a/.github/workflows/docker-build.yaml +++ b/.github/workflows/docker-build.yaml @@ -38,7 +38,7 @@ jobs: uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 with: tags: | - type=ref,enable=true,event=branch,prefix=collector- + type=ref,enable=true,event=branch,suffix=-collector images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # Build and push Docker image with Buildx (don't push on PR) @@ -77,7 +77,7 @@ jobs: uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 with: tags: | - type=ref,enable=true,event=branch,prefix=web- + type=ref,enable=true,event=branch,suffix=-web images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # Build and push Docker image with Buildx (don't push on PR) @@ -116,7 +116,7 @@ jobs: uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 with: tags: | - type=ref,enable=true,event=branch,prefix=omnibus- + type=ref,enable=true,event=branch,suffix=-omnibus images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # Build and push Docker image with Buildx (don't push on PR) From 1fc910f41b951cf8048d457c2032074cc193463f Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 25 Jul 2021 15:58:16 -0700 Subject: [PATCH 006/114] retest --- .github/workflows/docker-build.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml index aa03a25..a29e37b 100644 --- a/.github/workflows/docker-build.yaml +++ b/.github/workflows/docker-build.yaml @@ -11,7 +11,6 @@ env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} - jobs: collector: runs-on: ubuntu-latest From 80f46601308bd831a2ea6117f590ce6dee59aad0 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 25 Jul 2021 22:11:07 -0700 Subject: [PATCH 007/114] validate thresholds whenever SMART data is recieved. --- webapp/backend/pkg/database/interface.go | 2 + .../pkg/database/scrutiny_repository.go | 20 +++ .../backend/pkg/models/measurements/smart.go | 85 +++++---- .../measurements/smart_ata_attribute.go | 167 +++++++++--------- .../models/measurements/smart_attribute.go | 1 + .../measurements/smart_nvme_attribute.go | 51 +++--- .../measurements/smart_scsci_attribute.go | 48 ++--- .../ata_attribute_metadata.go | 2 +- .../nvme_attribute_metadata.go | 2 +- .../scsi_attribute_metadata.go | 2 +- .../pkg/web/handler/get_device_details.go | 8 +- .../pkg/web/handler/upload_device_metrics.go | 12 +- 12 files changed, 237 insertions(+), 163 deletions(-) rename webapp/backend/pkg/{metadata => thresholds}/ata_attribute_metadata.go (99%) rename webapp/backend/pkg/{metadata => thresholds}/nvme_attribute_metadata.go (99%) rename webapp/backend/pkg/{metadata => thresholds}/scsi_attribute_metadata.go (99%) diff --git a/webapp/backend/pkg/database/interface.go b/webapp/backend/pkg/database/interface.go index 5bca804..bc52475 100644 --- a/webapp/backend/pkg/database/interface.go +++ b/webapp/backend/pkg/database/interface.go @@ -2,6 +2,7 @@ package database import ( "context" + "github.com/analogj/scrutiny/webapp/backend/pkg" "github.com/analogj/scrutiny/webapp/backend/pkg/models" "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" @@ -16,6 +17,7 @@ type DeviceRepo interface { RegisterDevice(ctx context.Context, dev models.Device) error GetDevices(ctx context.Context) ([]models.Device, error) UpdateDevice(ctx context.Context, wwn string, collectorSmartData collector.SmartInfo) (models.Device, error) + UpdateDeviceStatus(ctx context.Context, wwn string, status pkg.DeviceStatus) (models.Device, error) GetDeviceDetails(ctx context.Context, wwn string) (models.Device, error) SaveSmartAttributes(ctx context.Context, wwn string, collectorSmartData collector.SmartInfo) (measurements.Smart, error) diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index a7711c1..bcfa20b 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -3,6 +3,7 @@ package database import ( "context" "fmt" + "github.com/analogj/scrutiny/webapp/backend/pkg" "github.com/analogj/scrutiny/webapp/backend/pkg/config" "github.com/analogj/scrutiny/webapp/backend/pkg/models" "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" @@ -163,6 +164,17 @@ func (sr *scrutinyRepository) UpdateDevice(ctx context.Context, wwn string, coll return device, sr.gormClient.Model(&device).Updates(device).Error } +//Update Device Status +func (sr *scrutinyRepository) UpdateDeviceStatus(ctx context.Context, wwn string, status pkg.DeviceStatus) (models.Device, error) { + var device models.Device + if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil { + return device, fmt.Errorf("Could not get device from DB", err) + } + + device.DeviceStatus = pkg.Set(device.DeviceStatus, status) + return device, sr.gormClient.Model(&device).Updates(device).Error +} + func (sr *scrutinyRepository) GetDeviceDetails(ctx context.Context, wwn string) (models.Device, error) { var device models.Device @@ -434,3 +446,11 @@ func (sr *scrutinyRepository) GetSummary(ctx context.Context) (map[string]*model return summaries, nil } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Process Thresholds +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +func (sr *scrutinyRepository) ProcessSmartAttributeThresholds() { + +} diff --git a/webapp/backend/pkg/models/measurements/smart.go b/webapp/backend/pkg/models/measurements/smart.go index 20524ff..315bd11 100644 --- a/webapp/backend/pkg/models/measurements/smart.go +++ b/webapp/backend/pkg/models/measurements/smart.go @@ -3,8 +3,8 @@ package measurements import ( "fmt" "github.com/analogj/scrutiny/webapp/backend/pkg" - "github.com/analogj/scrutiny/webapp/backend/pkg/metadata" "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" + "github.com/analogj/scrutiny/webapp/backend/pkg/thresholds" "log" "strings" "time" @@ -22,6 +22,9 @@ type Smart struct { //Attributes (fields) Attributes map[string]SmartAttribute `json:"attrs"` + + //status + Status pkg.DeviceStatus } func (sm *Smart) Flatten() (tags map[string]string, fields map[string]interface{}) { @@ -133,6 +136,7 @@ func (sm *Smart) FromCollectorSmartInfo(wwn string, info collector.SmartInfo) er //generate SmartAtaAttribute entries from Scrutiny Collector Smart data. func (sm *Smart) ProcessAtaSmartInfo(info collector.SmartInfo) { + sm.Status = pkg.DeviceStatusPassed for _, collectorAttr := range info.AtaSmartAttributes.Table { attrModel := SmartAtaAttribute{ AttributeId: collectorAttr.ID, @@ -146,53 +150,72 @@ func (sm *Smart) ProcessAtaSmartInfo(info collector.SmartInfo) { } //now that we've parsed the data from the smartctl response, lets match it against our metadata rules and add additional Scrutiny specific data. - if smartMetadata, ok := metadata.AtaMetadata[collectorAttr.ID]; ok { + if smartMetadata, ok := thresholds.AtaMetadata[collectorAttr.ID]; ok { attrModel.Name = smartMetadata.DisplayName if smartMetadata.Transform != nil { attrModel.TransformedValue = smartMetadata.Transform(attrModel.Value, attrModel.RawValue, attrModel.RawString) } } + attrModel.PopulateAttributeStatus() sm.Attributes[string(collectorAttr.ID)] = &attrModel + if attrModel.Status == pkg.SmartAttributeStatusFailed { + sm.Status = pkg.DeviceStatusFailedScrutiny + } } } //generate SmartNvmeAttribute entries from Scrutiny Collector Smart data. func (sm *Smart) ProcessNvmeSmartInfo(info collector.SmartInfo) { + sm.Attributes = map[string]SmartAttribute{ - "critical_warning": &SmartNvmeAttribute{AttributeId: "critical_warning", Name: "Critical Warning", Value: info.NvmeSmartHealthInformationLog.CriticalWarning, Threshold: 0}, - "temperature": &SmartNvmeAttribute{AttributeId: "temperature", Name: "Temperature", Value: info.NvmeSmartHealthInformationLog.Temperature, Threshold: -1}, - "available_spare": &SmartNvmeAttribute{AttributeId: "available_spare", Name: "Available Spare", Value: info.NvmeSmartHealthInformationLog.AvailableSpare, Threshold: info.NvmeSmartHealthInformationLog.AvailableSpareThreshold}, - "percentage_used": &SmartNvmeAttribute{AttributeId: "percentage_used", Name: "Percentage Used", Value: info.NvmeSmartHealthInformationLog.PercentageUsed, Threshold: 100}, - "data_units_read": &SmartNvmeAttribute{AttributeId: "data_units_read", Name: "Data Units Read", Value: info.NvmeSmartHealthInformationLog.DataUnitsRead, Threshold: -1}, - "data_units_written": &SmartNvmeAttribute{AttributeId: "data_units_written", Name: "Data Units Written", Value: info.NvmeSmartHealthInformationLog.DataUnitsWritten, Threshold: -1}, - "host_reads": &SmartNvmeAttribute{AttributeId: "host_reads", Name: "Host Reads", Value: info.NvmeSmartHealthInformationLog.HostReads, Threshold: -1}, - "host_writes": &SmartNvmeAttribute{AttributeId: "host_writes", Name: "Host Writes", Value: info.NvmeSmartHealthInformationLog.HostWrites, Threshold: -1}, - "controller_busy_time": &SmartNvmeAttribute{AttributeId: "controller_busy_time", Name: "Controller Busy Time", Value: info.NvmeSmartHealthInformationLog.ControllerBusyTime, Threshold: -1}, - "power_cycles": &SmartNvmeAttribute{AttributeId: "power_cycles", Name: "Power Cycles", Value: info.NvmeSmartHealthInformationLog.PowerCycles, Threshold: -1}, - "power_on_hours": &SmartNvmeAttribute{AttributeId: "power_on_hours", Name: "Power on Hours", Value: info.NvmeSmartHealthInformationLog.PowerOnHours, Threshold: -1}, - "unsafe_shutdowns": &SmartNvmeAttribute{AttributeId: "unsafe_shutdowns", Name: "Unsafe Shutdowns", Value: info.NvmeSmartHealthInformationLog.UnsafeShutdowns, Threshold: -1}, - "media_errors": &SmartNvmeAttribute{AttributeId: "media_errors", Name: "Media Errors", Value: info.NvmeSmartHealthInformationLog.MediaErrors, Threshold: 0}, - "num_err_log_entries": &SmartNvmeAttribute{AttributeId: "num_err_log_entries", Name: "Numb Err Log Entries", Value: info.NvmeSmartHealthInformationLog.NumErrLogEntries, Threshold: 0}, - "warning_temp_time": &SmartNvmeAttribute{AttributeId: "warning_temp_time", Name: "Warning Temp Time", Value: info.NvmeSmartHealthInformationLog.WarningTempTime, Threshold: -1}, - "critical_comp_time": &SmartNvmeAttribute{AttributeId: "critical_comp_time", Name: "Critical CompTime", Value: info.NvmeSmartHealthInformationLog.CriticalCompTime, Threshold: -1}, + "critical_warning": (&SmartNvmeAttribute{AttributeId: "critical_warning", Name: "Critical Warning", Value: info.NvmeSmartHealthInformationLog.CriticalWarning, Threshold: 0}).PopulateAttributeStatus(), + "temperature": (&SmartNvmeAttribute{AttributeId: "temperature", Name: "Temperature", Value: info.NvmeSmartHealthInformationLog.Temperature, Threshold: -1}).PopulateAttributeStatus(), + "available_spare": (&SmartNvmeAttribute{AttributeId: "available_spare", Name: "Available Spare", Value: info.NvmeSmartHealthInformationLog.AvailableSpare, Threshold: info.NvmeSmartHealthInformationLog.AvailableSpareThreshold}).PopulateAttributeStatus(), + "percentage_used": (&SmartNvmeAttribute{AttributeId: "percentage_used", Name: "Percentage Used", Value: info.NvmeSmartHealthInformationLog.PercentageUsed, Threshold: 100}).PopulateAttributeStatus(), + "data_units_read": (&SmartNvmeAttribute{AttributeId: "data_units_read", Name: "Data Units Read", Value: info.NvmeSmartHealthInformationLog.DataUnitsRead, Threshold: -1}).PopulateAttributeStatus(), + "data_units_written": (&SmartNvmeAttribute{AttributeId: "data_units_written", Name: "Data Units Written", Value: info.NvmeSmartHealthInformationLog.DataUnitsWritten, Threshold: -1}).PopulateAttributeStatus(), + "host_reads": (&SmartNvmeAttribute{AttributeId: "host_reads", Name: "Host Reads", Value: info.NvmeSmartHealthInformationLog.HostReads, Threshold: -1}).PopulateAttributeStatus(), + "host_writes": (&SmartNvmeAttribute{AttributeId: "host_writes", Name: "Host Writes", Value: info.NvmeSmartHealthInformationLog.HostWrites, Threshold: -1}).PopulateAttributeStatus(), + "controller_busy_time": (&SmartNvmeAttribute{AttributeId: "controller_busy_time", Name: "Controller Busy Time", Value: info.NvmeSmartHealthInformationLog.ControllerBusyTime, Threshold: -1}).PopulateAttributeStatus(), + "power_cycles": (&SmartNvmeAttribute{AttributeId: "power_cycles", Name: "Power Cycles", Value: info.NvmeSmartHealthInformationLog.PowerCycles, Threshold: -1}).PopulateAttributeStatus(), + "power_on_hours": (&SmartNvmeAttribute{AttributeId: "power_on_hours", Name: "Power on Hours", Value: info.NvmeSmartHealthInformationLog.PowerOnHours, Threshold: -1}).PopulateAttributeStatus(), + "unsafe_shutdowns": (&SmartNvmeAttribute{AttributeId: "unsafe_shutdowns", Name: "Unsafe Shutdowns", Value: info.NvmeSmartHealthInformationLog.UnsafeShutdowns, Threshold: -1}).PopulateAttributeStatus(), + "media_errors": (&SmartNvmeAttribute{AttributeId: "media_errors", Name: "Media Errors", Value: info.NvmeSmartHealthInformationLog.MediaErrors, Threshold: 0}).PopulateAttributeStatus(), + "num_err_log_entries": (&SmartNvmeAttribute{AttributeId: "num_err_log_entries", Name: "Numb Err Log Entries", Value: info.NvmeSmartHealthInformationLog.NumErrLogEntries, Threshold: 0}).PopulateAttributeStatus(), + "warning_temp_time": (&SmartNvmeAttribute{AttributeId: "warning_temp_time", Name: "Warning Temp Time", Value: info.NvmeSmartHealthInformationLog.WarningTempTime, Threshold: -1}).PopulateAttributeStatus(), + "critical_comp_time": (&SmartNvmeAttribute{AttributeId: "critical_comp_time", Name: "Critical CompTime", Value: info.NvmeSmartHealthInformationLog.CriticalCompTime, Threshold: -1}).PopulateAttributeStatus(), + } + + //find analyzed attribute status + for _, val := range sm.Attributes { + if val.GetStatus() == pkg.SmartAttributeStatusFailed { + sm.Status = pkg.DeviceStatusFailedScrutiny + } } } //generate SmartScsiAttribute entries from Scrutiny Collector Smart data. func (sm *Smart) ProcessScsiSmartInfo(info collector.SmartInfo) { sm.Attributes = map[string]SmartAttribute{ - "scsi_grown_defect_list": &SmartScsiAttribute{AttributeId: "scsi_grown_defect_list", Name: "Grown Defect List", Value: info.ScsiGrownDefectList, Threshold: 0}, - "read_errors_corrected_by_eccfast": &SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccfast", Name: "Read Errors Corrected by ECC Fast", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccfast, Threshold: -1}, - "read_errors_corrected_by_eccdelayed": &SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccdelayed", Name: "Read Errors Corrected by ECC Delayed", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccdelayed, Threshold: -1}, - "read_errors_corrected_by_rereads_rewrites": &SmartScsiAttribute{AttributeId: "read_errors_corrected_by_rereads_rewrites", Name: "Read Errors Corrected by ReReads/ReWrites", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByRereadsRewrites, Threshold: 0}, - "read_total_errors_corrected": &SmartScsiAttribute{AttributeId: "read_total_errors_corrected", Name: "Read Total Errors Corrected", Value: info.ScsiErrorCounterLog.Read.TotalErrorsCorrected, Threshold: -1}, - "read_correction_algorithm_invocations": &SmartScsiAttribute{AttributeId: "read_correction_algorithm_invocations", Name: "Read Correction Algorithm Invocations", Value: info.ScsiErrorCounterLog.Read.CorrectionAlgorithmInvocations, Threshold: -1}, - "read_total_uncorrected_errors": &SmartScsiAttribute{AttributeId: "read_total_uncorrected_errors", Name: "Read Total Uncorrected Errors", Value: info.ScsiErrorCounterLog.Read.TotalUncorrectedErrors, Threshold: 0}, - "write_errors_corrected_by_eccfast": &SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccfast", Name: "Write Errors Corrected by ECC Fast", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccfast, Threshold: -1}, - "write_errors_corrected_by_eccdelayed": &SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccdelayed", Name: "Write Errors Corrected by ECC Delayed", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccdelayed, Threshold: -1}, - "write_errors_corrected_by_rereads_rewrites": &SmartScsiAttribute{AttributeId: "write_errors_corrected_by_rereads_rewrites", Name: "Write Errors Corrected by ReReads/ReWrites", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByRereadsRewrites, Threshold: 0}, - "write_total_errors_corrected": &SmartScsiAttribute{AttributeId: "write_total_errors_corrected", Name: "Write Total Errors Corrected", Value: info.ScsiErrorCounterLog.Write.TotalErrorsCorrected, Threshold: -1}, - "write_correction_algorithm_invocations": &SmartScsiAttribute{AttributeId: "write_correction_algorithm_invocations", Name: "Write Correction Algorithm Invocations", Value: info.ScsiErrorCounterLog.Write.CorrectionAlgorithmInvocations, Threshold: -1}, - "write_total_uncorrected_errors": &SmartScsiAttribute{AttributeId: "write_total_uncorrected_errors", Name: "Write Total Uncorrected Errors", Value: info.ScsiErrorCounterLog.Write.TotalUncorrectedErrors, Threshold: 0}, + "scsi_grown_defect_list": (&SmartScsiAttribute{AttributeId: "scsi_grown_defect_list", Name: "Grown Defect List", Value: info.ScsiGrownDefectList, Threshold: 0}).PopulateAttributeStatus(), + "read_errors_corrected_by_eccfast": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccfast", Name: "Read Errors Corrected by ECC Fast", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccfast, Threshold: -1}).PopulateAttributeStatus(), + "read_errors_corrected_by_eccdelayed": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccdelayed", Name: "Read Errors Corrected by ECC Delayed", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccdelayed, Threshold: -1}).PopulateAttributeStatus(), + "read_errors_corrected_by_rereads_rewrites": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_rereads_rewrites", Name: "Read Errors Corrected by ReReads/ReWrites", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByRereadsRewrites, Threshold: 0}).PopulateAttributeStatus(), + "read_total_errors_corrected": (&SmartScsiAttribute{AttributeId: "read_total_errors_corrected", Name: "Read Total Errors Corrected", Value: info.ScsiErrorCounterLog.Read.TotalErrorsCorrected, Threshold: -1}).PopulateAttributeStatus(), + "read_correction_algorithm_invocations": (&SmartScsiAttribute{AttributeId: "read_correction_algorithm_invocations", Name: "Read Correction Algorithm Invocations", Value: info.ScsiErrorCounterLog.Read.CorrectionAlgorithmInvocations, Threshold: -1}).PopulateAttributeStatus(), + "read_total_uncorrected_errors": (&SmartScsiAttribute{AttributeId: "read_total_uncorrected_errors", Name: "Read Total Uncorrected Errors", Value: info.ScsiErrorCounterLog.Read.TotalUncorrectedErrors, Threshold: 0}).PopulateAttributeStatus(), + "write_errors_corrected_by_eccfast": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccfast", Name: "Write Errors Corrected by ECC Fast", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccfast, Threshold: -1}).PopulateAttributeStatus(), + "write_errors_corrected_by_eccdelayed": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccdelayed", Name: "Write Errors Corrected by ECC Delayed", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccdelayed, Threshold: -1}).PopulateAttributeStatus(), + "write_errors_corrected_by_rereads_rewrites": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_rereads_rewrites", Name: "Write Errors Corrected by ReReads/ReWrites", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByRereadsRewrites, Threshold: 0}).PopulateAttributeStatus(), + "write_total_errors_corrected": (&SmartScsiAttribute{AttributeId: "write_total_errors_corrected", Name: "Write Total Errors Corrected", Value: info.ScsiErrorCounterLog.Write.TotalErrorsCorrected, Threshold: -1}).PopulateAttributeStatus(), + "write_correction_algorithm_invocations": (&SmartScsiAttribute{AttributeId: "write_correction_algorithm_invocations", Name: "Write Correction Algorithm Invocations", Value: info.ScsiErrorCounterLog.Write.CorrectionAlgorithmInvocations, Threshold: -1}).PopulateAttributeStatus(), + "write_total_uncorrected_errors": (&SmartScsiAttribute{AttributeId: "write_total_uncorrected_errors", Name: "Write Total Uncorrected Errors", Value: info.ScsiErrorCounterLog.Write.TotalUncorrectedErrors, Threshold: 0}).PopulateAttributeStatus(), + } + + //find analyzed attribute status + for _, val := range sm.Attributes { + if val.GetStatus() == pkg.SmartAttributeStatusFailed { + sm.Status = pkg.DeviceStatusFailedScrutiny + } } } diff --git a/webapp/backend/pkg/models/measurements/smart_ata_attribute.go b/webapp/backend/pkg/models/measurements/smart_ata_attribute.go index 691cac7..6481b4f 100644 --- a/webapp/backend/pkg/models/measurements/smart_ata_attribute.go +++ b/webapp/backend/pkg/models/measurements/smart_ata_attribute.go @@ -2,14 +2,12 @@ package measurements import ( "fmt" + "github.com/analogj/scrutiny/webapp/backend/pkg" + "github.com/analogj/scrutiny/webapp/backend/pkg/thresholds" "strconv" "strings" ) -const SmartAttributeStatusPassed = "passed" -const SmartAttributeStatusFailed = "failed" -const SmartAttributeStatusWarning = "warn" - type SmartAtaAttribute struct { AttributeId int `json:"attribute_id"` Name string `json:"name"` @@ -27,6 +25,10 @@ type SmartAtaAttribute struct { FailureRate float64 `json:"failure_rate,omitempty"` } +func (sa *SmartAtaAttribute) GetStatus() string { + return sa.Status +} + func (sa *SmartAtaAttribute) Flatten() map[string]interface{} { idString := strconv.Itoa(sa.AttributeId) @@ -71,81 +73,82 @@ func (sa *SmartAtaAttribute) Inflate(key string, val interface{}) { } } -// -////populate attribute status, using SMART Thresholds & Observed Metadata -//func (sa *SmartAtaAttribute) PopulateAttributeStatus() { -// if strings.ToUpper(sa.WhenFailed) == SmartWhenFailedFailingNow { -// //this attribute has previously failed -// sa.Status = SmartAttributeStatusFailed -// sa.StatusReason = "Attribute is failing manufacturer SMART threshold" -// -// } else if strings.ToUpper(sa.WhenFailed) == SmartWhenFailedInThePast { -// sa.Status = SmartAttributeStatusWarning -// sa.StatusReason = "Attribute has previously failed manufacturer SMART threshold" -// } -// -// if smartMetadata, ok := metadata.AtaMetadata[sa.AttributeId]; ok { -// sa.MetadataObservedThresholdStatus(smartMetadata) -// } -// -// //check if status is blank, set to "passed" -// if len(sa.Status) == 0 { -// sa.Status = SmartAttributeStatusPassed -// } -//} -// -//// compare the attribute (raw, normalized, transformed) value to observed thresholds, and update status if necessary -//func (sa *SmartAtaAttribute) MetadataObservedThresholdStatus(smartMetadata metadata.AtaAttributeMetadata) { -// //TODO: multiple rules -// // try to predict the failure rates for observed thresholds that have 0 failure rate and error bars. -// // - if the attribute is critical -// // - the failure rate is over 10 - set to failed -// // - the attribute does not match any threshold, set to warn -// // - if the attribute is not critical -// // - if failure rate is above 20 - set to failed -// // - if failure rate is above 10 but below 20 - set to warn -// -// //update the smart attribute status based on Observed thresholds. -// var value int64 -// if smartMetadata.DisplayType == metadata.AtaSmartAttributeDisplayTypeNormalized { -// value = int64(sa.Value) -// } else if smartMetadata.DisplayType == metadata.AtaSmartAttributeDisplayTypeTransformed { -// value = sa.TransformedValue -// } else { -// value = sa.RawValue -// } -// -// for _, obsThresh := range smartMetadata.ObservedThresholds { -// -// //check if "value" is in this bucket -// if ((obsThresh.Low == obsThresh.High) && value == obsThresh.Low) || -// (obsThresh.Low < value && value <= obsThresh.High) { -// sa.FailureRate = obsThresh.AnnualFailureRate -// -// if smartMetadata.Critical { -// if obsThresh.AnnualFailureRate >= 0.10 { -// sa.Status = SmartAttributeStatusFailed -// sa.StatusReason = "Observed Failure Rate for Critical Attribute is greater than 10%" -// } -// } else { -// if obsThresh.AnnualFailureRate >= 0.20 { -// sa.Status = SmartAttributeStatusFailed -// sa.StatusReason = "Observed Failure Rate for Attribute is greater than 20%" -// } else if obsThresh.AnnualFailureRate >= 0.10 { -// sa.Status = SmartAttributeStatusWarning -// sa.StatusReason = "Observed Failure Rate for Attribute is greater than 10%" -// } -// } -// -// //we've found the correct bucket, we can drop out of this loop -// return -// } -// } -// // no bucket found -// if smartMetadata.Critical { -// sa.Status = SmartAttributeStatusWarning -// sa.StatusReason = "Could not determine Observed Failure Rate for Critical Attribute" -// } -// -// return -//} +//populate attribute status, using SMART Thresholds & Observed Metadata +// Chainable +func (sa *SmartAtaAttribute) PopulateAttributeStatus() *SmartAtaAttribute { + if strings.ToUpper(sa.WhenFailed) == pkg.SmartWhenFailedFailingNow { + //this attribute has previously failed + sa.Status = pkg.SmartAttributeStatusFailed + sa.StatusReason = "Attribute is failing manufacturer SMART threshold" + + } else if strings.ToUpper(sa.WhenFailed) == pkg.SmartWhenFailedInThePast { + sa.Status = pkg.SmartAttributeStatusWarning + sa.StatusReason = "Attribute has previously failed manufacturer SMART threshold" + } + + if smartMetadata, ok := thresholds.AtaMetadata[sa.AttributeId]; ok { + sa.ValidateThreshold(smartMetadata) + } + + //check if status is blank, set to "passed" + if len(sa.Status) == 0 { + sa.Status = pkg.SmartAttributeStatusPassed + } + return sa +} + +// compare the attribute (raw, normalized, transformed) value to observed thresholds, and update status if necessary +func (sa *SmartAtaAttribute) ValidateThreshold(smartMetadata thresholds.AtaAttributeMetadata) { + //TODO: multiple rules + // try to predict the failure rates for observed thresholds that have 0 failure rate and error bars. + // - if the attribute is critical + // - the failure rate is over 10 - set to failed + // - the attribute does not match any threshold, set to warn + // - if the attribute is not critical + // - if failure rate is above 20 - set to failed + // - if failure rate is above 10 but below 20 - set to warn + + //update the smart attribute status based on Observed thresholds. + var value int64 + if smartMetadata.DisplayType == thresholds.AtaSmartAttributeDisplayTypeNormalized { + value = int64(sa.Value) + } else if smartMetadata.DisplayType == thresholds.AtaSmartAttributeDisplayTypeTransformed { + value = sa.TransformedValue + } else { + value = sa.RawValue + } + + for _, obsThresh := range smartMetadata.ObservedThresholds { + + //check if "value" is in this bucket + if ((obsThresh.Low == obsThresh.High) && value == obsThresh.Low) || + (obsThresh.Low < value && value <= obsThresh.High) { + sa.FailureRate = obsThresh.AnnualFailureRate + + if smartMetadata.Critical { + if obsThresh.AnnualFailureRate >= 0.10 { + sa.Status = pkg.SmartAttributeStatusFailed + sa.StatusReason = "Observed Failure Rate for Critical Attribute is greater than 10%" + } + } else { + if obsThresh.AnnualFailureRate >= 0.20 { + sa.Status = pkg.SmartAttributeStatusFailed + sa.StatusReason = "Observed Failure Rate for Attribute is greater than 20%" + } else if obsThresh.AnnualFailureRate >= 0.10 { + sa.Status = pkg.SmartAttributeStatusWarning + sa.StatusReason = "Observed Failure Rate for Attribute is greater than 10%" + } + } + + //we've found the correct bucket, we can drop out of this loop + return + } + } + // no bucket found + if smartMetadata.Critical { + sa.Status = pkg.SmartAttributeStatusWarning + sa.StatusReason = "Could not determine Observed Failure Rate for Critical Attribute" + } + + return +} diff --git a/webapp/backend/pkg/models/measurements/smart_attribute.go b/webapp/backend/pkg/models/measurements/smart_attribute.go index 1d93bc8..a8aaea6 100644 --- a/webapp/backend/pkg/models/measurements/smart_attribute.go +++ b/webapp/backend/pkg/models/measurements/smart_attribute.go @@ -3,4 +3,5 @@ package measurements type SmartAttribute interface { Flatten() (fields map[string]interface{}) Inflate(key string, val interface{}) + GetStatus() string } diff --git a/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go b/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go index 2705ea9..80f1687 100644 --- a/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go +++ b/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go @@ -2,6 +2,8 @@ package measurements import ( "fmt" + "github.com/analogj/scrutiny/webapp/backend/pkg" + "github.com/analogj/scrutiny/webapp/backend/pkg/thresholds" "strings" ) @@ -17,6 +19,10 @@ type SmartNvmeAttribute struct { FailureRate float64 `json:"failure_rate,omitempty"` } +func (sa *SmartNvmeAttribute) GetStatus() string { + return sa.Status +} + func (sa *SmartNvmeAttribute) Flatten() map[string]interface{} { return map[string]interface{}{ fmt.Sprintf("attr.%s.attribute_id", sa.AttributeId): sa.AttributeId, @@ -44,25 +50,26 @@ func (sa *SmartNvmeAttribute) Inflate(key string, val interface{}) { } } -// -////populate attribute status, using SMART Thresholds & Observed Metadata -//func (sa *SmartNvmeAttribute) PopulateAttributeStatus() { -// -// //-1 is a special number meaning no threshold. -// if sa.Threshold != -1 { -// if smartMetadata, ok := metadata.NmveMetadata[sa.AttributeId]; ok { -// //check what the ideal is. Ideal tells us if we our recorded value needs to be above, or below the threshold -// if (smartMetadata.Ideal == "low" && sa.Value > sa.Threshold) || -// (smartMetadata.Ideal == "high" && sa.Value < sa.Threshold) { -// sa.Status = SmartAttributeStatusFailed -// sa.StatusReason = "Attribute is failing recommended SMART threshold" -// } -// } -// } -// //TODO: eventually figure out the critical_warning bits and determine correct error messages here. -// -// //check if status is blank, set to "passed" -// if len(sa.Status) == 0 { -// sa.Status = SmartAttributeStatusPassed -// } -//} +//populate attribute status, using SMART Thresholds & Observed Metadata +// Chainable +func (sa *SmartNvmeAttribute) PopulateAttributeStatus() *SmartNvmeAttribute { + + //-1 is a special number meaning no threshold. + if sa.Threshold != -1 { + if smartMetadata, ok := thresholds.NmveMetadata[sa.AttributeId]; ok { + //check what the ideal is. Ideal tells us if we our recorded value needs to be above, or below the threshold + if (smartMetadata.Ideal == "low" && sa.Value > sa.Threshold) || + (smartMetadata.Ideal == "high" && sa.Value < sa.Threshold) { + sa.Status = pkg.SmartAttributeStatusFailed + sa.StatusReason = "Attribute is failing recommended SMART threshold" + } + } + } + //TODO: eventually figure out the critical_warning bits and determine correct error messages here. + + //check if status is blank, set to "passed" + if len(sa.Status) == 0 { + sa.Status = pkg.SmartAttributeStatusPassed + } + return sa +} diff --git a/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go b/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go index 830036c..d692cef 100644 --- a/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go +++ b/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go @@ -2,6 +2,8 @@ package measurements import ( "fmt" + "github.com/analogj/scrutiny/webapp/backend/pkg" + "github.com/analogj/scrutiny/webapp/backend/pkg/thresholds" "strings" ) @@ -17,6 +19,10 @@ type SmartScsiAttribute struct { FailureRate float64 `json:"failure_rate,omitempty"` } +func (sa *SmartScsiAttribute) GetStatus() string { + return sa.Status +} + func (sa *SmartScsiAttribute) Flatten() map[string]interface{} { return map[string]interface{}{ fmt.Sprintf("attr.%s.attribute_id", sa.AttributeId): sa.AttributeId, @@ -45,23 +51,25 @@ func (sa *SmartScsiAttribute) Inflate(key string, val interface{}) { } // -////populate attribute status, using SMART Thresholds & Observed Metadata -//func (sa *SmartScsiAttribute) PopulateAttributeStatus() { -// -// //-1 is a special number meaning no threshold. -// if sa.Threshold != -1 { -// if smartMetadata, ok := metadata.NmveMetadata[sa.AttributeId]; ok { -// //check what the ideal is. Ideal tells us if we our recorded value needs to be above, or below the threshold -// if (smartMetadata.Ideal == "low" && sa.Value > sa.Threshold) || -// (smartMetadata.Ideal == "high" && sa.Value < sa.Threshold) { -// sa.Status = SmartAttributeStatusFailed -// sa.StatusReason = "Attribute is failing recommended SMART threshold" -// } -// } -// } -// -// //check if status is blank, set to "passed" -// if len(sa.Status) == 0 { -// sa.Status = SmartAttributeStatusPassed -// } -//} +//populate attribute status, using SMART Thresholds & Observed Metadata +//Chainable +func (sa *SmartScsiAttribute) PopulateAttributeStatus() *SmartScsiAttribute { + + //-1 is a special number meaning no threshold. + if sa.Threshold != -1 { + if smartMetadata, ok := thresholds.NmveMetadata[sa.AttributeId]; ok { + //check what the ideal is. Ideal tells us if we our recorded value needs to be above, or below the threshold + if (smartMetadata.Ideal == "low" && sa.Value > sa.Threshold) || + (smartMetadata.Ideal == "high" && sa.Value < sa.Threshold) { + sa.Status = pkg.SmartAttributeStatusFailed + sa.StatusReason = "Attribute is failing recommended SMART threshold" + } + } + } + + //check if status is blank, set to "passed" + if len(sa.Status) == 0 { + sa.Status = pkg.SmartAttributeStatusPassed + } + return sa +} diff --git a/webapp/backend/pkg/metadata/ata_attribute_metadata.go b/webapp/backend/pkg/thresholds/ata_attribute_metadata.go similarity index 99% rename from webapp/backend/pkg/metadata/ata_attribute_metadata.go rename to webapp/backend/pkg/thresholds/ata_attribute_metadata.go index 2f4c6c8..0628a18 100644 --- a/webapp/backend/pkg/metadata/ata_attribute_metadata.go +++ b/webapp/backend/pkg/thresholds/ata_attribute_metadata.go @@ -1,4 +1,4 @@ -package metadata +package thresholds const AtaSmartAttributeDisplayTypeRaw = "raw" const AtaSmartAttributeDisplayTypeNormalized = "normalized" diff --git a/webapp/backend/pkg/metadata/nvme_attribute_metadata.go b/webapp/backend/pkg/thresholds/nvme_attribute_metadata.go similarity index 99% rename from webapp/backend/pkg/metadata/nvme_attribute_metadata.go rename to webapp/backend/pkg/thresholds/nvme_attribute_metadata.go index 80efcfa..8ac4c8d 100644 --- a/webapp/backend/pkg/metadata/nvme_attribute_metadata.go +++ b/webapp/backend/pkg/thresholds/nvme_attribute_metadata.go @@ -1,4 +1,4 @@ -package metadata +package thresholds // https://media.kingston.com/support/downloads/MKP_521.6_SMART-DCP1000_attribute.pdf // https://www.percona.com/blog/2017/02/09/using-nvme-command-line-tools-to-check-nvme-flash-health/ diff --git a/webapp/backend/pkg/metadata/scsi_attribute_metadata.go b/webapp/backend/pkg/thresholds/scsi_attribute_metadata.go similarity index 99% rename from webapp/backend/pkg/metadata/scsi_attribute_metadata.go rename to webapp/backend/pkg/thresholds/scsi_attribute_metadata.go index cd4f974..51cbbaa 100644 --- a/webapp/backend/pkg/metadata/scsi_attribute_metadata.go +++ b/webapp/backend/pkg/thresholds/scsi_attribute_metadata.go @@ -1,4 +1,4 @@ -package metadata +package thresholds type ScsiAttributeMetadata struct { ID string `json:"-"` diff --git a/webapp/backend/pkg/web/handler/get_device_details.go b/webapp/backend/pkg/web/handler/get_device_details.go index 5807292..d938c88 100644 --- a/webapp/backend/pkg/web/handler/get_device_details.go +++ b/webapp/backend/pkg/web/handler/get_device_details.go @@ -2,7 +2,7 @@ package handler import ( "github.com/analogj/scrutiny/webapp/backend/pkg/database" - "github.com/analogj/scrutiny/webapp/backend/pkg/metadata" + "github.com/analogj/scrutiny/webapp/backend/pkg/thresholds" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" "net/http" @@ -23,11 +23,11 @@ func GetDeviceDetails(c *gin.Context) { var deviceMetadata interface{} if device.IsAta() { - deviceMetadata = metadata.AtaMetadata + deviceMetadata = thresholds.AtaMetadata } else if device.IsNvme() { - deviceMetadata = metadata.NmveMetadata + deviceMetadata = thresholds.NmveMetadata } else if device.IsScsi() { - deviceMetadata = metadata.ScsiMetadata + deviceMetadata = thresholds.ScsiMetadata } c.JSON(http.StatusOK, gin.H{"success": true, "data": map[string]interface{}{"device": device, "smart_results": smartResults}, "metadata": deviceMetadata}) diff --git a/webapp/backend/pkg/web/handler/upload_device_metrics.go b/webapp/backend/pkg/web/handler/upload_device_metrics.go index 5abd134..9fab5b5 100644 --- a/webapp/backend/pkg/web/handler/upload_device_metrics.go +++ b/webapp/backend/pkg/web/handler/upload_device_metrics.go @@ -37,13 +37,23 @@ func UploadDeviceMetrics(c *gin.Context) { } // insert smart info - _, err = deviceRepo.SaveSmartAttributes(c, c.Param("wwn"), collectorSmartData) + smartData, err := deviceRepo.SaveSmartAttributes(c, c.Param("wwn"), collectorSmartData) if err != nil { logger.Errorln("An error occurred while saving smartctl metrics", err) c.JSON(http.StatusInternalServerError, gin.H{"success": false}) return } + if smartData.Status != pkg.DeviceStatusPassed { + //there is a failure detected by Scrutiny, update the device status on the homepage. + updatedDevice, err = deviceRepo.UpdateDeviceStatus(c, c.Param("wwn"), smartData.Status) + if err != nil { + logger.Errorln("An error occurred while updating device status", err) + c.JSON(http.StatusInternalServerError, gin.H{"success": false}) + return + } + } + // save smart temperature data (ignore failures) err = deviceRepo.SaveSmartTemperature(c, c.Param("wwn"), updatedDevice.DeviceProtocol, collectorSmartData) if err != nil { From bd19230cbffb7085dfe0db839aaf17fd1193bc38 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 25 Jul 2021 22:32:13 -0700 Subject: [PATCH 008/114] make sure data is persisted to DB. --- .../backend/pkg/database/scrutiny_repository.go | 8 -------- .../models/measurements/smart_ata_attribute.go | 17 +++++++++++++++++ .../models/measurements/smart_nvme_attribute.go | 16 ++++++++++++++++ .../measurements/smart_scsci_attribute.go | 16 ++++++++++++++++ 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index bcfa20b..58fc514 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -446,11 +446,3 @@ func (sr *scrutinyRepository) GetSummary(ctx context.Context) (map[string]*model return summaries, nil } - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Process Thresholds -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -func (sr *scrutinyRepository) ProcessSmartAttributeThresholds() { - -} diff --git a/webapp/backend/pkg/models/measurements/smart_ata_attribute.go b/webapp/backend/pkg/models/measurements/smart_ata_attribute.go index 6481b4f..230c124 100644 --- a/webapp/backend/pkg/models/measurements/smart_ata_attribute.go +++ b/webapp/backend/pkg/models/measurements/smart_ata_attribute.go @@ -42,6 +42,12 @@ func (sa *SmartAtaAttribute) Flatten() map[string]interface{} { fmt.Sprintf("attr.%s.raw_value", idString): sa.RawValue, fmt.Sprintf("attr.%s.raw_string", idString): sa.RawString, fmt.Sprintf("attr.%s.when_failed", idString): sa.WhenFailed, + + //Generated Data + fmt.Sprintf("attr.%s.transformed_value", idString): sa.TransformedValue, + fmt.Sprintf("attr.%s.status", idString): sa.Status, + fmt.Sprintf("attr.%s.status_reason", idString): sa.StatusReason, + fmt.Sprintf("attr.%s.failure_rate", idString): sa.FailureRate, } } func (sa *SmartAtaAttribute) Inflate(key string, val interface{}) { @@ -70,6 +76,17 @@ func (sa *SmartAtaAttribute) Inflate(key string, val interface{}) { sa.RawString = val.(string) case "when_failed": sa.WhenFailed = val.(string) + + //generated + case "transformed_value": + sa.TransformedValue = val.(int64) + case "status": + sa.Status = val.(string) + case "status_reason": + sa.StatusReason = val.(string) + case "failure_rate": + sa.FailureRate = val.(float64) + } } diff --git a/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go b/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go index 80f1687..0320824 100644 --- a/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go +++ b/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go @@ -29,6 +29,12 @@ func (sa *SmartNvmeAttribute) Flatten() map[string]interface{} { fmt.Sprintf("attr.%s.name", sa.AttributeId): sa.Name, fmt.Sprintf("attr.%s.value", sa.AttributeId): sa.Value, fmt.Sprintf("attr.%s.thresh", sa.AttributeId): sa.Threshold, + + //Generated Data + fmt.Sprintf("attr.%s.transformed_value", sa.AttributeId): sa.TransformedValue, + fmt.Sprintf("attr.%s.status", sa.AttributeId): sa.Status, + fmt.Sprintf("attr.%s.status_reason", sa.AttributeId): sa.StatusReason, + fmt.Sprintf("attr.%s.failure_rate", sa.AttributeId): sa.FailureRate, } } func (sa *SmartNvmeAttribute) Inflate(key string, val interface{}) { @@ -47,6 +53,16 @@ func (sa *SmartNvmeAttribute) Inflate(key string, val interface{}) { sa.Value = val.(int64) case "thresh": sa.Threshold = val.(int64) + + //generated + case "transformed_value": + sa.TransformedValue = val.(int64) + case "status": + sa.Status = val.(string) + case "status_reason": + sa.StatusReason = val.(string) + case "failure_rate": + sa.FailureRate = val.(float64) } } diff --git a/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go b/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go index d692cef..a2f1ea1 100644 --- a/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go +++ b/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go @@ -29,6 +29,12 @@ func (sa *SmartScsiAttribute) Flatten() map[string]interface{} { fmt.Sprintf("attr.%s.name", sa.AttributeId): sa.Name, fmt.Sprintf("attr.%s.value", sa.AttributeId): sa.Value, fmt.Sprintf("attr.%s.thresh", sa.AttributeId): sa.Threshold, + + //Generated Data + fmt.Sprintf("attr.%s.transformed_value", sa.AttributeId): sa.TransformedValue, + fmt.Sprintf("attr.%s.status", sa.AttributeId): sa.Status, + fmt.Sprintf("attr.%s.status_reason", sa.AttributeId): sa.StatusReason, + fmt.Sprintf("attr.%s.failure_rate", sa.AttributeId): sa.FailureRate, } } func (sa *SmartScsiAttribute) Inflate(key string, val interface{}) { @@ -47,6 +53,16 @@ func (sa *SmartScsiAttribute) Inflate(key string, val interface{}) { sa.Value = val.(int64) case "thresh": sa.Threshold = val.(int64) + + //generated + case "transformed_value": + sa.TransformedValue = val.(int64) + case "status": + sa.Status = val.(string) + case "status_reason": + sa.StatusReason = val.(string) + case "failure_rate": + sa.FailureRate = val.(float64) } } From c8768387f6205634f85cc762ac34745c1407ec0c Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 25 Jul 2021 14:51:28 -0700 Subject: [PATCH 009/114] adding docker build -> ghcr.io --- .github/workflows/docker-build.yaml | 53 +++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/workflows/docker-build.yaml diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml new file mode 100644 index 0000000..337b6c8 --- /dev/null +++ b/.github/workflows/docker-build.yaml @@ -0,0 +1,53 @@ +name: Docker +on: + schedule: + - cron: '36 12 * * *' + push: + branches: [ master, influxdb ] + # Publish semver tags as releases. + tags: [ 'v*.*.*' ] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} From c97388ff60b3dd756348170599880ec1084559ed Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 25 Jul 2021 15:39:30 -0700 Subject: [PATCH 010/114] tagging. --- .github/workflows/docker-build.yaml | 82 ++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml index 337b6c8..a7c1685 100644 --- a/.github/workflows/docker-build.yaml +++ b/.github/workflows/docker-build.yaml @@ -13,8 +13,7 @@ env: jobs: - build: - + collector: runs-on: ubuntu-latest permissions: contents: read @@ -23,7 +22,45 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + tags: | + type=ref,enable=true,event=branch,prefix=collector- + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + file: docker/Dockerfile.collector + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + web: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v2 # Login against a Docker registry except on PR # https://github.com/docker/login-action - name: Log into registry ${{ env.REGISTRY }} @@ -33,13 +70,53 @@ jobs: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + tags: | + type=ref,enable=true,event=branch,prefix=web- + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + file: docker/Dockerfile.web + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + omnibus: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} # Extract metadata (tags, labels) for Docker # https://github.com/docker/metadata-action - name: Extract Docker metadata id: meta uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 with: + tags: | + type=ref,enable=true,event=branch,prefix=omnibus- images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # Build and push Docker image with Buildx (don't push on PR) @@ -48,6 +125,7 @@ jobs: uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc with: context: . + file: docker/Dockerfile push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From b197d349f46fe863aca267dbb8a480921e13a6d4 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 25 Jul 2021 15:52:07 -0700 Subject: [PATCH 011/114] setting the image type as suffix. --- .github/workflows/docker-build.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml index a7c1685..aa03a25 100644 --- a/.github/workflows/docker-build.yaml +++ b/.github/workflows/docker-build.yaml @@ -38,7 +38,7 @@ jobs: uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 with: tags: | - type=ref,enable=true,event=branch,prefix=collector- + type=ref,enable=true,event=branch,suffix=-collector images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # Build and push Docker image with Buildx (don't push on PR) @@ -77,7 +77,7 @@ jobs: uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 with: tags: | - type=ref,enable=true,event=branch,prefix=web- + type=ref,enable=true,event=branch,suffix=-web images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # Build and push Docker image with Buildx (don't push on PR) @@ -116,7 +116,7 @@ jobs: uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 with: tags: | - type=ref,enable=true,event=branch,prefix=omnibus- + type=ref,enable=true,event=branch,suffix=-omnibus images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # Build and push Docker image with Buildx (don't push on PR) From a60edfff268f19c949f691701fb802af2d483d78 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 1 Aug 2021 10:42:38 -0700 Subject: [PATCH 012/114] fixing mocked data --- webapp/frontend/package-lock.json | 18471 +++++++++++++++- .../src/app/data/mock/device/details/sdc.ts | 197 + .../src/app/data/mock/device/details/sdd.ts | 100 + .../src/app/data/mock/device/details/sde.ts | 36 +- .../src/app/data/mock/device/details/sdf.ts | 414 +- 5 files changed, 19127 insertions(+), 91 deletions(-) diff --git a/webapp/frontend/package-lock.json b/webapp/frontend/package-lock.json index f2ac183..cae08a9 100644 --- a/webapp/frontend/package-lock.json +++ b/webapp/frontend/package-lock.json @@ -1,8 +1,18345 @@ { "name": "@treo/starter", "version": "1.0.1", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "@treo/starter", + "version": "1.0.1", + "license": "https://themeforest.net/licenses/standard", + "dependencies": { + "@angular/animations": "9.1.4", + "@angular/cdk": "9.2.2", + "@angular/common": "9.1.4", + "@angular/compiler": "9.1.4", + "@angular/core": "9.1.4", + "@angular/forms": "9.1.4", + "@angular/material": "9.2.2", + "@angular/material-moment-adapter": "9.2.2", + "@angular/platform-browser": "9.1.4", + "@angular/platform-browser-dynamic": "9.1.4", + "@angular/router": "9.1.4", + "@fullcalendar/angular": "4.4.5-beta", + "@fullcalendar/core": "4.4.0", + "@fullcalendar/daygrid": "4.4.0", + "@fullcalendar/interaction": "4.4.0", + "@fullcalendar/list": "4.4.0", + "@fullcalendar/moment": "4.4.0", + "@fullcalendar/rrule": "4.4.0", + "@fullcalendar/timegrid": "4.4.0", + "@types/humanize-duration": "^3.18.1", + "apexcharts": "3.19.0", + "crypto-js": "3.3.0", + "highlight.js": "10.0.1", + "humanize-duration": "^3.24.0", + "lodash": "4.17.15", + "moment": "2.24.0", + "ng-apexcharts": "1.2.3", + "ngx-markdown": "9.0.0", + "ngx-quill": "9.1.0", + "perfect-scrollbar": "1.5.0", + "quill": "1.3.7", + "rrule": "2.6.4", + "rxjs": "6.5.5", + "tslib": "1.11.1", + "web-animations-js": "2.3.2", + "zone.js": "0.10.3" + }, + "devDependencies": { + "@angular-devkit/build-angular": "0.901.4", + "@angular/cli": "9.1.4", + "@angular/compiler-cli": "9.1.4", + "@angular/language-service": "9.1.4", + "@types/crypto-js": "3.1.45", + "@types/highlight.js": "9.12.3", + "@types/jasmine": "3.5.10", + "@types/jasminewd2": "2.0.8", + "@types/lodash": "4.14.150", + "@types/node": "12.12.37", + "codelyzer": "5.2.2", + "jasmine-core": "3.5.0", + "jasmine-spec-reporter": "4.2.1", + "karma": "5.0.4", + "karma-chrome-launcher": "3.1.0", + "karma-coverage-istanbul-reporter": "2.1.1", + "karma-jasmine": "3.0.3", + "karma-jasmine-html-reporter": "1.5.3", + "protractor": "5.4.4", + "tailwindcss": "1.4.4", + "ts-node": "8.3.0", + "tslint": "6.1.2", + "typescript": "3.8.3" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.901.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.901.4.tgz", + "integrity": "sha512-w4RMj7eLhUSh70HUy5tW4EXjLQFXk0Lfr9WiSy5gvPGp+zzYxknI+Wn4Xid1wU/WS+4tuMv5nJIaNaH2sABESQ==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "9.1.4", + "rxjs": "6.5.4" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 6.11.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/architect/node_modules/rxjs": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/build-angular": { + "version": "0.901.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.901.4.tgz", + "integrity": "sha512-Vod4bc6d38fuvqauIDQxKMe9hKW9m4QNzPKxEc+Dv5Xkv95WaGzkbUVu8M8t4E//sDDMpmcPdYOXSdR27WBi2Q==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.901.4", + "@angular-devkit/build-optimizer": "0.901.4", + "@angular-devkit/build-webpack": "0.901.4", + "@angular-devkit/core": "9.1.4", + "@babel/core": "7.9.0", + "@babel/generator": "7.9.3", + "@babel/preset-env": "7.9.0", + "@babel/template": "7.8.6", + "@jsdevtools/coverage-istanbul-loader": "3.0.3", + "@ngtools/webpack": "9.1.4", + "ajv": "6.12.0", + "autoprefixer": "9.7.4", + "babel-loader": "8.0.6", + "browserslist": "^4.9.1", + "cacache": "15.0.0", + "caniuse-lite": "^1.0.30001032", + "circular-dependency-plugin": "5.2.0", + "copy-webpack-plugin": "5.1.1", + "core-js": "3.6.4", + "css-loader": "3.5.1", + "cssnano": "4.1.10", + "file-loader": "6.0.0", + "find-cache-dir": "3.3.1", + "glob": "7.1.6", + "jest-worker": "25.1.0", + "karma-source-map-support": "1.4.0", + "less": "3.11.1", + "less-loader": "5.0.0", + "license-webpack-plugin": "2.1.4", + "loader-utils": "2.0.0", + "mini-css-extract-plugin": "0.9.0", + "minimatch": "3.0.4", + "open": "7.0.3", + "parse5": "4.0.0", + "postcss": "7.0.27", + "postcss-import": "12.0.1", + "postcss-loader": "3.0.0", + "raw-loader": "4.0.0", + "regenerator-runtime": "0.13.5", + "rimraf": "3.0.2", + "rollup": "2.1.0", + "rxjs": "6.5.4", + "sass": "1.26.3", + "sass-loader": "8.0.2", + "semver": "7.1.3", + "source-map": "0.7.3", + "source-map-loader": "0.2.4", + "speed-measure-webpack-plugin": "1.3.1", + "style-loader": "1.1.3", + "stylus": "0.54.7", + "stylus-loader": "3.0.2", + "terser": "4.6.10", + "terser-webpack-plugin": "2.3.5", + "tree-kill": "1.2.2", + "webpack": "4.42.0", + "webpack-dev-middleware": "3.7.2", + "webpack-dev-server": "3.10.3", + "webpack-merge": "4.2.2", + "webpack-sources": "1.4.3", + "webpack-subresource-integrity": "1.4.0", + "worker-plugin": "4.0.2" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 6.11.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": ">=9.0.0 < 10", + "typescript": ">=3.6 < 3.9" + }, + "peerDependenciesMeta": { + "@angular/localize": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/generator": { + "version": "7.9.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.3.tgz", + "integrity": "sha512-RpxM252EYsz9qLUIq6F7YJyK1sv0wWDBFuztfDGWaQKzHjqDHysxSiRUpA/X9jmfqo+WzkAVKFaUily5h+gDCQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.9.0", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/generator/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular-devkit/build-angular/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/@angular-devkit/build-angular/node_modules/parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/semver": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.3.tgz", + "integrity": "sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular-devkit/build-optimizer": { + "version": "0.901.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.901.4.tgz", + "integrity": "sha512-iDMlNRwd8ICMBKnycfw55hdnL5kCiqUjQn+aK/4uOMJMz49tiYMNJAaznXX2BFKmYSmbapKjEbzx9yMYRi9Y7w==", + "dev": true, + "dependencies": { + "loader-utils": "2.0.0", + "source-map": "0.7.3", + "tslib": "1.11.1", + "typescript": "3.6.5", + "webpack-sources": "1.4.3" + }, + "bin": { + "build-optimizer": "src/build-optimizer/cli.js" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 6.11.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/build-optimizer/node_modules/typescript": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.5.tgz", + "integrity": "sha512-BEjlc0Z06ORZKbtcxGrIvvwYs5hAnuo6TKdNFL55frVDlB+na3z5bsLhFaIxmT+dPWgBIjMo6aNnTOgHHmHgiQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.901.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.901.4.tgz", + "integrity": "sha512-YBOufI4TGAtIDCS6erFygYJX/fkd8xwI58d+7iFIBmtIJC4/fpGjX6qkHMCBgh8HXAkEPSORBCYQn9O44J1ZXQ==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.901.4", + "@angular-devkit/core": "9.1.4", + "rxjs": "6.5.4" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 6.11.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^4.6.0", + "webpack-dev-server": "^3.1.4" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-9.1.4.tgz", + "integrity": "sha512-OPFQDmT4XabLMSRDgmnzedlOrc83DzQIgLcfoh/UhZ7aJKf/2Vq4l09p/DkMNI36vN5BRL0zDZt7TjvKNgyYgA==", + "dev": true, + "dependencies": { + "ajv": "6.12.0", + "fast-json-stable-stringify": "2.1.0", + "magic-string": "0.25.7", + "rxjs": "6.5.4", + "source-map": "0.7.3" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 6.11.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/core/node_modules/rxjs": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-9.1.4.tgz", + "integrity": "sha512-RAbdnUEZ3JTLmWSBiXT5trsVx8Fi72fxN9CiRaluM09Cytg6BUc1wC5XCO0YPvhI400+3Ro1nwjPXezjg7LXzQ==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "9.1.4", + "ora": "4.0.3", + "rxjs": "6.5.4" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 6.11.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/rxjs": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular/animations": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-9.1.4.tgz", + "integrity": "sha512-gMo/DbCm5BDArladMAeC7/75T2DvhLr4CSUGJt/P/aimTEG2ywoAALs3pzwSSe4qxrHiR0OIksVW3l4km3iXEw==", + "peerDependencies": { + "@angular/core": "9.1.4", + "tslib": "^1.10.0" + } + }, + "node_modules/@angular/cdk": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-9.2.2.tgz", + "integrity": "sha512-VNd+KuMN6cBcy4/8OyMxqYaxdjPP6IyCqIVijB2JREkc5Sg4VWmPgx2L3rHt/DzjsVBVRgx35uqOMymDezG3jQ==", + "optionalDependencies": { + "parse5": "^5.0.0" + }, + "peerDependencies": { + "@angular/common": "^9.0.0 || ^10.0.0-0", + "@angular/core": "^9.0.0 || ^10.0.0-0", + "tslib": "^1.9.0" + } + }, + "node_modules/@angular/cli": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-9.1.4.tgz", + "integrity": "sha512-H9MqoT4zyIv+Yo3cvRVkzafWGHsqt7jUvtvGwMHIDMTfEX+Q8yiYlDLL6WM3Eb6/hDmLcRGC/GI495sKS1z5qA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@angular-devkit/architect": "0.901.4", + "@angular-devkit/core": "9.1.4", + "@angular-devkit/schematics": "9.1.4", + "@schematics/angular": "9.1.4", + "@schematics/update": "0.901.4", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.1", + "debug": "4.1.1", + "ini": "1.3.5", + "inquirer": "7.1.0", + "npm-package-arg": "8.0.1", + "npm-pick-manifest": "6.0.0", + "open": "7.0.3", + "pacote": "9.5.12", + "read-package-tree": "5.3.1", + "rimraf": "3.0.2", + "semver": "7.1.3", + "symbol-observable": "1.2.0", + "universal-analytics": "0.4.20", + "uuid": "7.0.2" + }, + "bin": { + "ng": "bin/ng" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 6.11.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/cli/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@angular/cli/node_modules/semver": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.3.tgz", + "integrity": "sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/cli/node_modules/uuid": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.2.tgz", + "integrity": "sha512-vy9V/+pKG+5ZTYKf+VcphF5Oc6EFiu3W8Nv3P3zIh0EqVI80ZxOzuPfe9EHjkFNvf8+xuTHVeei4Drydlx4zjw==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@angular/common": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-9.1.4.tgz", + "integrity": "sha512-JvCoCWVbx0tF7l/0WTi24ui/mc2SElyVSNchR4VK/FViARnkvnSBdI/Ef5QWXrsPyKU4PYBtnWWgyxRspH+FBA==", + "peerDependencies": { + "@angular/core": "9.1.4", + "rxjs": "^6.5.3", + "tslib": "^1.10.0" + } + }, + "node_modules/@angular/compiler": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.1.4.tgz", + "integrity": "sha512-B+f3lviFNEJtL9V9exSKYPSz2Ddb6dxgPzQR7GSjGikDo+fKMtC1PjNwgJooS9gavhQx30uwkEEMIPYQbM6nNA==", + "peerDependencies": { + "tslib": "^1.10.0" + } + }, + "node_modules/@angular/compiler-cli": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-9.1.4.tgz", + "integrity": "sha512-n3PzqNnPD7s/AF9mv5CnarK0sgfoq4txFncHjJWBSltuTQoz6BDZyjuEdqsSLUvgAZPeLsmohemOzEE38HYHZA==", + "dev": true, + "dependencies": { + "canonical-path": "1.0.0", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.7.2", + "fs-extra": "4.0.2", + "magic-string": "^0.25.0", + "minimist": "^1.2.0", + "reflect-metadata": "^0.1.2", + "semver": "^6.3.0", + "source-map": "^0.6.1", + "sourcemap-codec": "^1.4.8", + "yargs": "15.3.0" + }, + "bin": { + "ivy-ngcc": "ngcc/main-ivy-ngcc.js", + "ng-xi18n": "src/extract_i18n.js", + "ngc": "src/main.js", + "ngcc": "ngcc/main-ngcc.js" + }, + "engines": { + "node": ">=10.0" + }, + "peerDependencies": { + "@angular/compiler": "9.1.4", + "tslib": "^1.10.0", + "typescript": ">=3.6 <3.9" + } + }, + "node_modules/@angular/compiler-cli/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@angular/compiler-cli/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "dependencies": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@angular/compiler-cli/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/@angular/compiler-cli/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/@angular/compiler-cli/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/@angular/compiler-cli/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@angular/compiler-cli/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/@angular/compiler-cli/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/@angular/compiler-cli/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@angular/compiler-cli/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular/compiler-cli/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@angular/compiler-cli/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@angular/compiler-cli/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/@angular/compiler-cli/node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/@angular/compiler-cli/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/@angular/compiler-cli/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@angular/compiler-cli/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@angular/compiler-cli/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@angular/compiler-cli/node_modules/yargs": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.0.tgz", + "integrity": "sha512-g/QCnmjgOl1YJjGsnUg2SatC7NUYEiLXJqxNOQU9qSpjzGtGXda9b+OKccr1kLTy8BN9yqEyqfq5lxlwdc13TA==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@angular/compiler-cli/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@angular/core": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.1.4.tgz", + "integrity": "sha512-ND240vncmVD2KVe/KSQU3d/DxxoRipFg1+jFOFZGt0n0orCBHk/V1fu9iaG1sRyldL0+rCQ+fTI+1N4DTmMnxA==", + "peerDependencies": { + "rxjs": "^6.5.3", + "tslib": "^1.10.0", + "zone.js": "~0.10.3" + } + }, + "node_modules/@angular/forms": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-9.1.4.tgz", + "integrity": "sha512-Njt+pMLfPBchL0/ayIjJqXL6ZfM4Ccvf7KO1wS1HMzh3QlmfNa0JSgc4pfrbRJAMN9g7V/FYLyKejs1bJZkenA==", + "peerDependencies": { + "@angular/common": "9.1.4", + "@angular/core": "9.1.4", + "@angular/platform-browser": "9.1.4", + "rxjs": "^6.5.3", + "tslib": "^1.10.0" + } + }, + "node_modules/@angular/language-service": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-9.1.4.tgz", + "integrity": "sha512-eyVxxiegdb4ESdFGfkuDN+YfUbOVHRQLjIl6ACFJQDNHzVXzbmuqpyr5hIJANIVady103/7+dqRxxJo1DdIdTQ==", + "dev": true + }, + "node_modules/@angular/material": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-9.2.2.tgz", + "integrity": "sha512-gdQiMJ6PtW/5fd+0mglHFyzxULDCBGjn9RTET3sUq2rkc9+jBXr4OvnsUyBWSnqqv97XqotVDIx5JgE4/YX/Rw==", + "peerDependencies": { + "@angular/animations": "^9.0.0 || ^10.0.0-0", + "@angular/cdk": "9.2.2", + "@angular/common": "^9.0.0 || ^10.0.0-0", + "@angular/core": "^9.0.0 || ^10.0.0-0", + "@angular/forms": "^9.0.0 || ^10.0.0-0", + "tslib": "^1.9.0" + } + }, + "node_modules/@angular/material-moment-adapter": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-9.2.2.tgz", + "integrity": "sha512-hijj2VVC7Oy9XGVYE+FsdI521w/9v453jP2VUH+CCRoeoCopdNS+dh1vacSAGf21UXwH9LJ5E6kI9RsmfwF/Ig==", + "peerDependencies": { + "@angular/core": "^9.0.0 || ^10.0.0-0", + "@angular/material": "9.2.2", + "moment": "^2.18.1", + "tslib": "^1.9.0" + } + }, + "node_modules/@angular/platform-browser": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-9.1.4.tgz", + "integrity": "sha512-mBCHfTl+5tQfaUiGlDujP7mFBzovFc54Zi2kcCE8DSdSSVQ2TPBo6hXa6y2cL3hJPFZzQ7mC4ORFrsGADhHn/w==", + "peerDependencies": { + "@angular/animations": "9.1.4", + "@angular/common": "9.1.4", + "@angular/core": "9.1.4", + "tslib": "^1.10.0" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/platform-browser-dynamic": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.1.4.tgz", + "integrity": "sha512-YtVbnxyS6FU7xNpA6A95tmSfrB8+WC7OH3mbP8M9NaGk0OYz8B/JOe1HByP4JRpEGCvBtXdJ2NSW/MpLIT8SiQ==", + "peerDependencies": { + "@angular/common": "9.1.4", + "@angular/compiler": "9.1.4", + "@angular/core": "9.1.4", + "@angular/platform-browser": "9.1.4", + "tslib": "^1.10.0" + } + }, + "node_modules/@angular/router": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-9.1.4.tgz", + "integrity": "sha512-yUyjCgG2P2Jh8MvoyC6yirmAtx1Qe7MKLuLvsa9WOB571QNEcNLTYMfAMHUKsQTcE/+o984QyLlneoibgI9wFA==", + "peerDependencies": { + "@angular/common": "9.1.4", + "@angular/core": "9.1.4", + "@angular/platform-browser": "9.1.4", + "rxjs": "^6.5.3", + "tslib": "^1.10.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.8.3" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.9.6.tgz", + "integrity": "sha512-5QPTrNen2bm7RBc7dsOmcA5hbrS4O2Vhmk5XOL4zWW/zD/hV0iinpefDlkm+tBBy8kDtFaaeEvmAqt+nURAV2g==", + "dev": true, + "dependencies": { + "browserslist": "^4.11.1", + "invariant": "^2.2.4", + "semver": "^5.5.0" + } + }, + "node_modules/@babel/compat-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/core": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", + "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.0", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helpers": "^7.9.0", + "@babel/parser": "^7.9.0", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.9.0", + "@babel/types": "^7.9.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/@babel/generator": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.6.tgz", + "integrity": "sha512-+htwWKJbH2bL72HRluF8zumBxzuX0ZZUFl3JLNyoUjM/Ho8wnVpPXM6aUz8cfKDqQ/h7zHqKt4xzJteUosckqQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.9.6", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/core/node_modules/@babel/generator/node_modules/@babel/types": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.6.tgz", + "integrity": "sha512-qxXzvBO//jO9ZnoasKF1uJzHd2+M6Q2ZPIVfnFps8JJvXy0ZBbwbNOmE6SGIY5XOY6d1Bo5lb9d9RJ8nv3WSeA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.9.5", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@babel/core/node_modules/@babel/helper-validator-identifier": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", + "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", + "dev": true + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/core/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/generator/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz", + "integrity": "sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.8.3" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz", + "integrity": "sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw==", + "dev": true, + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.9.6.tgz", + "integrity": "sha512-x2Nvu0igO0ejXzx09B/1fGBxY9NXQlBW2kZsSxCJft+KHN8t9XWzIvFxtPHnBOAXpVsdxZKZFbRUC8TsNKajMw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.9.6", + "browserslist": "^4.11.1", + "invariant": "^2.2.4", + "levenary": "^1.1.1", + "semver": "^5.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.8.8", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz", + "integrity": "sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-regex": "^7.8.3", + "regexpu-core": "^4.7.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-map": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz", + "integrity": "sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.8.3", + "@babel/types": "^7.8.3", + "lodash": "^4.17.13" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz", + "integrity": "sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.8.3" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz", + "integrity": "sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.8.3" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", + "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.8.3" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", + "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.8.3" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz", + "integrity": "sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", + "@babel/helper-simple-access": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/template": "^7.8.6", + "@babel/types": "^7.9.0", + "lodash": "^4.17.13" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", + "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.8.3" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + }, + "node_modules/@babel/helper-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.8.3.tgz", + "integrity": "sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.13" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz", + "integrity": "sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-wrap-function": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.9.6.tgz", + "integrity": "sha512-qX+chbxkbArLyCImk3bWV+jB5gTNU/rsze+JlcF6Nf8tVTigPJSI1o1oBow/9Resa1yehUO9lIipsmu9oG4RzA==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/traverse": "^7.9.6", + "@babel/types": "^7.9.6" + } + }, + "node_modules/@babel/helper-replace-supers/node_modules/@babel/generator": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.6.tgz", + "integrity": "sha512-+htwWKJbH2bL72HRluF8zumBxzuX0ZZUFl3JLNyoUjM/Ho8wnVpPXM6aUz8cfKDqQ/h7zHqKt4xzJteUosckqQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.9.6", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/helper-replace-supers/node_modules/@babel/helper-function-name": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz", + "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.9.5" + } + }, + "node_modules/@babel/helper-replace-supers/node_modules/@babel/helper-validator-identifier": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", + "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", + "dev": true + }, + "node_modules/@babel/helper-replace-supers/node_modules/@babel/parser": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", + "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-replace-supers/node_modules/@babel/traverse": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.6.tgz", + "integrity": "sha512-b3rAHSjbxy6VEAvlxM8OV/0X4XrG72zoxme6q1MOoe2vd0bEc+TwayhuC1+Dfgqh1QEG+pj7atQqvUprHIccsg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.6", + "@babel/helper-function-name": "^7.9.5", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "node_modules/@babel/helper-replace-supers/node_modules/@babel/types": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.6.tgz", + "integrity": "sha512-qxXzvBO//jO9ZnoasKF1uJzHd2+M6Q2ZPIVfnFps8JJvXy0ZBbwbNOmE6SGIY5XOY6d1Bo5lb9d9RJ8nv3WSeA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.9.5", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@babel/helper-replace-supers/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", + "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.8.3" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz", + "integrity": "sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==", + "dev": true + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz", + "integrity": "sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "node_modules/@babel/helpers": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.6.tgz", + "integrity": "sha512-tI4bUbldloLcHWoRUMAj4g1bF313M/o6fBKhIsb3QnGVPwRm9JsNf/gqMkQ7zjqReABiffPV6RWj7hEglID5Iw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.9.6", + "@babel/types": "^7.9.6" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/generator": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.6.tgz", + "integrity": "sha512-+htwWKJbH2bL72HRluF8zumBxzuX0ZZUFl3JLNyoUjM/Ho8wnVpPXM6aUz8cfKDqQ/h7zHqKt4xzJteUosckqQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.9.6", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/helper-function-name": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz", + "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.9.5" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/helper-validator-identifier": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", + "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", + "dev": true + }, + "node_modules/@babel/helpers/node_modules/@babel/parser": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", + "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/traverse": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.6.tgz", + "integrity": "sha512-b3rAHSjbxy6VEAvlxM8OV/0X4XrG72zoxme6q1MOoe2vd0bEc+TwayhuC1+Dfgqh1QEG+pj7atQqvUprHIccsg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.6", + "@babel/helper-function-name": "^7.9.5", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/types": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.6.tgz", + "integrity": "sha512-qxXzvBO//jO9ZnoasKF1uJzHd2+M6Q2ZPIVfnFps8JJvXy0ZBbwbNOmE6SGIY5XOY6d1Bo5lb9d9RJ8nv3WSeA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.9.5", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@babel/helpers/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.9.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", + "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz", + "integrity": "sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-remap-async-to-generator": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz", + "integrity": "sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz", + "integrity": "sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz", + "integrity": "sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.6.tgz", + "integrity": "sha512-Ga6/fhGqA9Hj+y6whNpPv8psyaK5xzrQwSPsGPloVkvmH+PqW1ixdnfJ9uIO06OjQNYol3PMnfmJ8vfZtkzF+A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.9.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz", + "integrity": "sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.8.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz", + "integrity": "sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.8.8", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz", + "integrity": "sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz", + "integrity": "sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz", + "integrity": "sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz", + "integrity": "sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-remap-async-to-generator": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz", + "integrity": "sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz", + "integrity": "sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "lodash": "^4.17.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.5.tgz", + "integrity": "sha512-x2kZoIuLC//O5iA7PEvecB105o7TLzZo8ofBVhP79N+DO3jaX+KYfww9TQcfBEZD0nikNyYcGB1IKtRq36rdmg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-define-map": "^7.8.3", + "@babel/helper-function-name": "^7.9.5", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", + "@babel/helper-split-export-declaration": "^7.8.3", + "globals": "^11.1.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-function-name": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz", + "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.9.5" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-validator-identifier": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", + "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", + "dev": true + }, + "node_modules/@babel/plugin-transform-classes/node_modules/@babel/types": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.6.tgz", + "integrity": "sha512-qxXzvBO//jO9ZnoasKF1uJzHd2+M6Q2ZPIVfnFps8JJvXy0ZBbwbNOmE6SGIY5XOY6d1Bo5lb9d9RJ8nv3WSeA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.9.5", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz", + "integrity": "sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.9.5.tgz", + "integrity": "sha512-j3OEsGel8nHL/iusv/mRd5fYZ3DrOxWC82x0ogmdN/vHfAP4MYw+AFKYanzWlktNwikKvlzUV//afBW5FTp17Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz", + "integrity": "sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz", + "integrity": "sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz", + "integrity": "sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz", + "integrity": "sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz", + "integrity": "sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz", + "integrity": "sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz", + "integrity": "sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.6.tgz", + "integrity": "sha512-zoT0kgC3EixAyIAU+9vfaUVKTv9IxBDSabgHoUCBP6FqEJ+iNiN7ip7NBKcYqbfUDfuC2mFCbM7vbu4qJgOnDw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helper-plugin-utils": "^7.8.3", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.6.tgz", + "integrity": "sha512-7H25fSlLcn+iYimmsNe3uK1at79IE6SKW9q0/QeEHTMC9MdOZ+4bA+T1VFB5fgOqBWoqlifXRzYD0JPdmIrgSQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-simple-access": "^7.8.3", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.6.tgz", + "integrity": "sha512-NW5XQuW3N2tTHim8e1b7qGy7s0kZ2OH3m5octc49K1SdAKGxYxeIx7hiIz05kS1R2R+hOWcsr1eYwcGhrdHsrg==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.8.3", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helper-plugin-utils": "^7.8.3", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz", + "integrity": "sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz", + "integrity": "sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz", + "integrity": "sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz", + "integrity": "sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.5.tgz", + "integrity": "sha512-0+1FhHnMfj6lIIhVvS4KGQJeuhe1GI//h5uptK4PvLt+BGBxsoUJbd3/IW002yk//6sZPlFgsG1hY6OHLcy6kA==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz", + "integrity": "sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz", + "integrity": "sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA==", + "dev": true, + "dependencies": { + "regenerator-transform": "^0.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz", + "integrity": "sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz", + "integrity": "sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz", + "integrity": "sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz", + "integrity": "sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-regex": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz", + "integrity": "sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz", + "integrity": "sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz", + "integrity": "sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.9.0.tgz", + "integrity": "sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.9.0", + "@babel/helper-compilation-targets": "^7.8.7", + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-proposal-async-generator-functions": "^7.8.3", + "@babel/plugin-proposal-dynamic-import": "^7.8.3", + "@babel/plugin-proposal-json-strings": "^7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-proposal-numeric-separator": "^7.8.3", + "@babel/plugin-proposal-object-rest-spread": "^7.9.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.9.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.8.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.8.3", + "@babel/plugin-transform-async-to-generator": "^7.8.3", + "@babel/plugin-transform-block-scoped-functions": "^7.8.3", + "@babel/plugin-transform-block-scoping": "^7.8.3", + "@babel/plugin-transform-classes": "^7.9.0", + "@babel/plugin-transform-computed-properties": "^7.8.3", + "@babel/plugin-transform-destructuring": "^7.8.3", + "@babel/plugin-transform-dotall-regex": "^7.8.3", + "@babel/plugin-transform-duplicate-keys": "^7.8.3", + "@babel/plugin-transform-exponentiation-operator": "^7.8.3", + "@babel/plugin-transform-for-of": "^7.9.0", + "@babel/plugin-transform-function-name": "^7.8.3", + "@babel/plugin-transform-literals": "^7.8.3", + "@babel/plugin-transform-member-expression-literals": "^7.8.3", + "@babel/plugin-transform-modules-amd": "^7.9.0", + "@babel/plugin-transform-modules-commonjs": "^7.9.0", + "@babel/plugin-transform-modules-systemjs": "^7.9.0", + "@babel/plugin-transform-modules-umd": "^7.9.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", + "@babel/plugin-transform-new-target": "^7.8.3", + "@babel/plugin-transform-object-super": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.8.7", + "@babel/plugin-transform-property-literals": "^7.8.3", + "@babel/plugin-transform-regenerator": "^7.8.7", + "@babel/plugin-transform-reserved-words": "^7.8.3", + "@babel/plugin-transform-shorthand-properties": "^7.8.3", + "@babel/plugin-transform-spread": "^7.8.3", + "@babel/plugin-transform-sticky-regex": "^7.8.3", + "@babel/plugin-transform-template-literals": "^7.8.3", + "@babel/plugin-transform-typeof-symbol": "^7.8.4", + "@babel/plugin-transform-unicode-regex": "^7.8.3", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.9.0", + "browserslist": "^4.9.1", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "semver": "^5.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.3.tgz", + "integrity": "sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.6.tgz", + "integrity": "sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + } + }, + "node_modules/@babel/template": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" + } + }, + "node_modules/@babel/traverse": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.0.tgz", + "integrity": "sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.0", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.9.0", + "@babel/types": "^7.9.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.4.tgz", + "integrity": "sha512-rjP8ahaDy/ouhrvCoU1E5mqaitWrxwuNGU+dy1EpaoK48jZay4MdkskKGIMHLZNewg8sAsqpGSREJwP0zH3YQA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.9.0", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/traverse/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/types": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.0.tgz", + "integrity": "sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.9.0", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@fullcalendar/angular": { + "version": "4.4.5-beta", + "resolved": "https://registry.npmjs.org/@fullcalendar/angular/-/angular-4.4.5-beta.tgz", + "integrity": "sha512-L144YrgrgFr75/LGNcDDX9xKy465AZR/EqWPxkdNFgBSeeblH+kf8OMy8K6YcuJDlv4nXw4RucBqbMrrQKvbQw==", + "dependencies": { + "@fullcalendar/core": "~4.4.0", + "fast-deep-equal": "^3.1.1" + }, + "engines": { + "node": ">= 6.9.0", + "npm": ">= 3.0.0" + }, + "peerDependencies": { + "@angular/common": "^9.0.0", + "@angular/core": "^9.0.0", + "tslib": "^1.10.0" + } + }, + "node_modules/@fullcalendar/core": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-4.4.0.tgz", + "integrity": "sha512-PC4mmXHJHAlXmUEmZVnePyA8yYCOBdxBNq8yjJqedEtT1X0x36yTFz/Y0Ux6bniICZDqYtk0xoxe6jaxi++e0g==" + }, + "node_modules/@fullcalendar/daygrid": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-4.4.0.tgz", + "integrity": "sha512-pDfvL0XZxKHTZ4VFOmwaYe3LmuABEIZsEopeqQ8y5O6BDen9KCbJqgHeCI8FpASSBd6bNlUx7il7EHdSoHhgIw==", + "peerDependencies": { + "@fullcalendar/core": "~4.4.0" + } + }, + "node_modules/@fullcalendar/interaction": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-4.4.0.tgz", + "integrity": "sha512-nGu0ZzYYlNpIhqfyv3JupteWKFETs3W1MzbRJcEZkuPncn4BooEi4A2blgHfacHAmmpaNkT84tAmhzi734MFBA==", + "peerDependencies": { + "@fullcalendar/core": "~4.4.0" + } + }, + "node_modules/@fullcalendar/list": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@fullcalendar/list/-/list-4.4.0.tgz", + "integrity": "sha512-uUDSPS71czNTK5Z3x3HzeE3KIvqkCfvhY+mGFdaAL6+7VpCwEIfB6s3GIJOjzu9TONmczMk4jdq0b1WUFLY5PQ==", + "peerDependencies": { + "@fullcalendar/core": "~4.4.0" + } + }, + "node_modules/@fullcalendar/moment": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@fullcalendar/moment/-/moment-4.4.0.tgz", + "integrity": "sha512-sW2F7z0E1+kBvBduGiXVYJtIWj2AWeUQQoiLA+xgprsyljzigwnI+9J2iviaB9uL7LIbCSnPrOZmhpVTufmPvQ==", + "peerDependencies": { + "@fullcalendar/core": "~4.4.0", + "moment": "^2.24.0" + } + }, + "node_modules/@fullcalendar/rrule": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@fullcalendar/rrule/-/rrule-4.4.0.tgz", + "integrity": "sha512-pXe3kSShg9CQ5gr0J0IGMYAwVlBv6j9yotRfJUrCY7xUWNkqTLAmburW7Q7KNlDMOLuiFbM/twBYZYiIjjTWpg==", + "peerDependencies": { + "@fullcalendar/core": "~4.4.0", + "rrule": "^2.6.0" + } + }, + "node_modules/@fullcalendar/timegrid": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@fullcalendar/timegrid/-/timegrid-4.4.0.tgz", + "integrity": "sha512-QwJ9oM87/ZTbXaE8PMIVp20GPtVCFmroaeR1GydJ6BKYtbxG/nsaSv7RhqvDa2jLjHaTWC2NjHo9hRfjQjtCZA==", + "dependencies": { + "@fullcalendar/daygrid": "~4.4.0" + }, + "peerDependencies": { + "@fullcalendar/core": "~4.4.0" + } + }, + "node_modules/@fullhuman/postcss-purgecss": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-2.1.2.tgz", + "integrity": "sha512-Jf34YVBK9GtXTblpu0svNUJdA7rTQoRMz+yEJe6mwTnXDIGipWLzaX/VgU/x6IPC6WvU5SY/XlawwqhxoyFPTg==", + "dev": true, + "dependencies": { + "postcss": "7.0.27", + "purgecss": "^2.1.2" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jsdevtools/coverage-istanbul-loader": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/coverage-istanbul-loader/-/coverage-istanbul-loader-3.0.3.tgz", + "integrity": "sha512-TAdNkeGB5Fe4Og+ZkAr1Kvn9by2sfL44IAHFtxlh1BA1XJ5cLpO9iSNki5opWESv3l3vSHsZ9BNKuqFKbEbFaA==", + "dev": true, + "dependencies": { + "convert-source-map": "^1.7.0", + "istanbul-lib-instrument": "^4.0.1", + "loader-utils": "^1.4.0", + "merge-source-map": "^1.1.0", + "schema-utils": "^2.6.4" + } + }, + "node_modules/@jsdevtools/coverage-istanbul-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/@jsdevtools/coverage-istanbul-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/@ngtools/webpack": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-9.1.4.tgz", + "integrity": "sha512-CDlQzMnWraxf/dT3G5L+0N0VniWHWdzjLRP8pWBoyV0xlzWS1yL/lj8Mas2jEIuaUxZ8bi29mE7xa8prqewtBQ==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "9.1.4", + "enhanced-resolve": "4.1.1", + "rxjs": "6.5.4", + "webpack-sources": "1.4.3" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 6.11.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": ">=9.0.0 < 10", + "typescript": ">=3.6 < 3.9", + "webpack": "^4.0.0" + } + }, + "node_modules/@ngtools/webpack/node_modules/rxjs": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@schematics/angular": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-9.1.4.tgz", + "integrity": "sha512-7nbiYBRgXc+f0sa5iXTcF6/VMy/Xq0wyKKnDFiLCb2aFYR7EXRHWF2GuwDIg2bvFugLuCBDoNnXeddLE1TXGWg==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "9.1.4", + "@angular-devkit/schematics": "9.1.4" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 6.11.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@schematics/update": { + "version": "0.901.4", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.901.4.tgz", + "integrity": "sha512-jCtZY2Fbj502gKN5gdu1brnRy/ssyzTrWm69Ty73V+t8uL7nLr+/hny/VBJ8CiQnKQvxcgVl1xgvI1cXzpysVA==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "9.1.4", + "@angular-devkit/schematics": "9.1.4", + "@yarnpkg/lockfile": "1.1.0", + "ini": "1.3.5", + "npm-package-arg": "^8.0.0", + "pacote": "9.5.12", + "rxjs": "6.5.4", + "semver": "7.1.3", + "semver-intersect": "1.4.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 6.11.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@schematics/update/node_modules/rxjs": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@schematics/update/node_modules/semver": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.3.tgz", + "integrity": "sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "node_modules/@types/crypto-js": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-3.1.45.tgz", + "integrity": "sha512-/4yiILxQnVfpAtrVctuEl0qwqAToqayoPEvutyWhHPslr2D9sx85KRmIq7etC0ZYKCK8ppucoLzJukjJdAtfdA==", + "dev": true + }, + "node_modules/@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "node_modules/@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "dependencies": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/highlight.js": { + "version": "9.12.3", + "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.3.tgz", + "integrity": "sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ==", + "dev": true + }, + "node_modules/@types/humanize-duration": { + "version": "3.18.1", + "resolved": "https://registry.npmjs.org/@types/humanize-duration/-/humanize-duration-3.18.1.tgz", + "integrity": "sha512-MUgbY3CF7hg/a/jogixmAufLjJBQT7WEf8Q+kYJkOc47ytngg1IuZobCngdTjAgY83JWEogippge5O5fplaQlw==" + }, + "node_modules/@types/jasmine": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.5.10.tgz", + "integrity": "sha512-3F8qpwBAiVc5+HPJeXJpbrl+XjawGmciN5LgiO7Gv1pl1RHtjoMNqZpqEksaPJW05ViKe8snYInRs6xB25Xdew==", + "dev": true + }, + "node_modules/@types/jasminewd2": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.8.tgz", + "integrity": "sha512-d9p31r7Nxk0ZH0U39PTH0hiDlJ+qNVGjlt1ucOoTUptxb2v+Y5VMnsxfwN+i3hK4yQnqBi3FMmoMFcd1JHDxdg==", + "dev": true, + "dependencies": { + "@types/jasmine": "*" + } + }, + "node_modules/@types/lodash": { + "version": "4.14.150", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.150.tgz", + "integrity": "sha512-kMNLM5JBcasgYscD9x/Gvr6lTAv2NVgsKtet/hm93qMyf/D1pt+7jeEZklKJKxMVmXjxbRVQQGfqDSfipYCO6w==", + "dev": true + }, + "node_modules/@types/marked": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.7.3.tgz", + "integrity": "sha512-WXdEKuT3azHxLTThd5dwnpLt2Q9QiC8iKj09KZRtVqro3pX8hhY+GbD8FZOae6SBBEJ22yKJn3c7ejL0aucAcA==" + }, + "node_modules/@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "12.12.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.37.tgz", + "integrity": "sha512-4mXKoDptrXAwZErQHrLzpe0FN/0Wmf5JRniSVIdwUrtDf9wnmEV1teCNLBo/TwuXhkK/bVegoEn/wmb+x0AuPg==", + "dev": true + }, + "node_modules/@types/q": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", + "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", + "dev": true + }, + "node_modules/@types/selenium-webdriver": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.17.tgz", + "integrity": "sha512-tGomyEuzSC1H28y2zlW6XPCaDaXFaD6soTdb4GNdmte2qfHtrKqhy0ZFs4r/1hpazCfEZqeTSRLvSasmEx89uw==", + "dev": true + }, + "node_modules/@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "dev": true + }, + "node_modules/@types/webpack-sources": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.7.tgz", + "integrity": "sha512-XyaHrJILjK1VHVC4aVlKsdNN5KBTwufMb43cQs+flGxtPAf/1Qwl8+Q0tp5BwEGaI8D6XT1L+9bSWXckgkjTLw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.6.1" + } + }, + "node_modules/@types/webpack-sources/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/@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-code-frame": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "node_modules/@webassemblyjs/helper-fsm": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "node_modules/@webassemblyjs/wast-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "dev": true, + "dependencies": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "node_modules/acorn-node/node_modules/acorn": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", + "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adm-zip": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.14.tgz", + "integrity": "sha512-/9aQCnQHF+0IiCl0qhXoK7qs//SwYE7zX8lsr/DNk1BRAHYxeLZPL4pguwK29gUEqasYQjqPtEpDRSWEkdHn9g==", + "dev": true, + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", + "dev": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", + "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "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" + } + }, + "node_modules/ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true, + "peerDependencies": { + "ajv": ">=5.0.0" + } + }, + "node_modules/ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "node_modules/ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "dependencies": { + "type-fest": "^0.11.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/apexcharts": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.19.0.tgz", + "integrity": "sha512-fzupCGVDvOoU6kEzguLAfgRgrlHynHM5fnkkyCL85tYf9U8bw1hCijs4A+kWXurC/SNytJrArBc21kA/2wuHYg==", + "dependencies": { + "svg.draggable.js": "^2.2.2", + "svg.easing.js": "^2.0.0", + "svg.filter.js": "^2.0.2", + "svg.pathmorphing.js": "^0.1.3", + "svg.resize.js": "^1.4.3", + "svg.select.js": "^3.0.1" + }, + "funding": { + "url": "https://github.com/apexcharts/apexcharts.js?sponsor=1" + } + }, + "node_modules/app-root-path": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.2.1.tgz", + "integrity": "sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA==", + "dev": true, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "dependencies": { + "default-require-extensions": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "dev": true, + "dependencies": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "node_modules/asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "dependencies": { + "object-assign": "^4.1.1", + "util": "0.10.3" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assert/node_modules/inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "node_modules/assert/node_modules/util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "dependencies": { + "inherits": "2.0.1" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", + "dev": true + }, + "node_modules/async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/autoprefixer": { + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.4.tgz", + "integrity": "sha512-g0Ya30YrMBAEZk60lp+qfX5YQllG+S5W3GYCFvyHTvhOki0AEQJLPEcIuGRsqVwLi8FvXPVtwTGhfr38hVpm0g==", + "dev": true, + "dependencies": { + "browserslist": "^4.8.3", + "caniuse-lite": "^1.0.30001020", + "chalk": "^2.4.2", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.26", + "postcss-value-parser": "^4.0.2" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==", + "dev": true + }, + "node_modules/axobject-query": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", + "dev": true, + "dependencies": { + "ast-types-flow": "0.0.7" + } + }, + "node_modules/babel-loader": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz", + "integrity": "sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw==", + "dev": true, + "dependencies": { + "find-cache-dir": "^2.0.0", + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1", + "pify": "^4.0.1" + }, + "engines": { + "node": ">= 6.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/babel-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/babel-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "node_modules/base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "dependencies": { + "callsite": "1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "dev": true + }, + "node_modules/blocking-proxy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", + "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "blocking-proxy": "built/lib/bin.js" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "dependencies": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.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/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "dependencies": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserslist": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.12.0.tgz", + "integrity": "sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001043", + "electron-to-chromium": "^1.3.413", + "node-releases": "^1.1.53", + "pkg-up": "^2.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + }, + "node_modules/browserstack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.0.tgz", + "integrity": "sha512-HJDJ0TSlmkwnt9RZ+v5gFpa1XZTBYTj0ywvLwJ3241J7vMw2jAsGNVhKHtmCOyg+VxeLZyaibO9UL71AsUeDIw==", + "dev": true, + "dependencies": { + "https-proxy-agent": "^2.2.1" + } + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "node_modules/builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "dev": true + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.0.tgz", + "integrity": "sha512-L0JpXHhplbJSiDGzyJJnJCTL7er7NzbBgxzVqLswEb4bO91Zbv17OUMuUeu/q0ZwKn3V+1HM4wb9tO4eVE/K8g==", + "dev": true, + "dependencies": { + "chownr": "^1.1.2", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "move-concurrently": "^1.0.1", + "p-map": "^3.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^2.7.1", + "ssri": "^8.0.0", + "tar": "^6.0.1", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cacache/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "dependencies": { + "callsites": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/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-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001048", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001048.tgz", + "integrity": "sha512-g1iSHKVxornw0K8LG9LLdf+Fxnv7T1Z+mMsf0/YYLclQX4Cd522Ap0Lrw6NFqHgezit78dtyWxzlV2Xfc7vgRg==", + "dev": true + }, + "node_modules/canonical-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz", + "integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==", + "dev": true + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "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/chokidar": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz", + "integrity": "sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.4.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/circular-dependency-plugin": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.0.tgz", + "integrity": "sha512-7p4Kn/gffhQaavNfyDFg7LS5S/UT1JAjyGd4UqR2+jzoYF02eDkj0Ec3+48TsIa4zghjLY87nQHIh/ecK9qLdw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "webpack": ">=4.0.1" + } + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-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.3.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.3.0.tgz", + "integrity": "sha512-Xs2Hf2nzrvJMFKimOR7YR0QwZ8fc0u98kdtwN1eNAZzNQgH3vK2pXzff6GJtKh7S5hoJ87ECiAiZFS2fb5Ii2w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "node_modules/clipboard": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz", + "integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==", + "optional": true, + "dependencies": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "node_modules/cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "dependencies": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dev": true, + "dependencies": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/codelyzer": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-5.2.2.tgz", + "integrity": "sha512-jB4FZ1Sx7kZhvZVdf+N2BaKTdrrNZOL0Bj10RRfrhHrb3zEvXjJvvq298JPMJAiyiCS/v4zs1QlGU0ip7xGqeA==", + "dev": true, + "dependencies": { + "app-root-path": "^2.2.1", + "aria-query": "^3.0.0", + "axobject-query": "2.0.2", + "css-selector-tokenizer": "^0.7.1", + "cssauron": "^1.4.0", + "damerau-levenshtein": "^1.0.4", + "semver-dsl": "^1.0.1", + "source-map": "^0.5.7", + "sprintf-js": "^1.1.2" + }, + "peerDependencies": { + "@angular/compiler": ">=2.3.1 <10.0.0 || >9.0.0-beta <10.0.0 || >9.1.0-beta <10.0.0 || >9.2.0-beta <10.0.0", + "@angular/core": ">=2.3.1 <10.0.0 || >9.0.0-beta <10.0.0 || >9.1.0-beta <10.0.0 || >9.2.0-beta <10.0.0", + "tslint": "^5.0.0 || ^6.0.0" + } + }, + "node_modules/codelyzer/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/codelyzer/node_modules/sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", + "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "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": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "dev": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "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==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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==" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "node_modules/compare-versions": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", + "dev": true + }, + "node_modules/component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "node_modules/component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "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" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "node_modules/copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "dependencies": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "node_modules/copy-concurrently/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz", + "integrity": "sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg==", + "dev": true, + "dependencies": { + "cacache": "^12.0.3", + "find-cache-dir": "^2.1.0", + "glob-parent": "^3.1.0", + "globby": "^7.1.1", + "is-glob": "^4.0.1", + "loader-utils": "^1.2.3", + "minimatch": "^3.0.4", + "normalize-path": "^3.0.0", + "p-limit": "^2.2.1", + "schema-utils": "^1.0.0", + "serialize-javascript": "^2.1.2", + "webpack-log": "^2.0.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/copy-webpack-plugin/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/copy-webpack-plugin/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/copy-webpack-plugin/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "dependencies": { + "figgy-pudding": "^3.5.1" + } + }, + "node_modules/core-js": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz", + "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", + "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", + "dev": true, + "dependencies": { + "browserslist": "^4.8.5", + "semver": "7.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/crypto-js": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", + "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==" + }, + "node_modules/css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + } + }, + "node_modules/css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/css-declaration-sorter": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.1", + "timsort": "^0.3.0" + }, + "engines": { + "node": ">4" + } + }, + "node_modules/css-loader": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.5.1.tgz", + "integrity": "sha512-0G4CbcZzQ9D1Q6ndOfjFuMDo8uLYMu5vc9Abs5ztyHcKvmil6GJrMiNjzzi3tQvUF+mVRuDg7bE6Oc0Prolgig==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.27", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.0.3", + "schema-utils": "^2.6.5", + "semver": "^6.3.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/css-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/css-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/css-parse": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", + "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=", + "dev": true, + "dependencies": { + "css": "^2.0.0" + } + }, + "node_modules/css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "node_modules/css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", + "dev": true + }, + "node_modules/css-selector-tokenizer": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.2.tgz", + "integrity": "sha512-yj856NGuAymN6r8bn8/Jl46pR+OC3eEvAhfGYDUe7YPtTPAYrSSw4oAniZ9Y8T5B92hjhwTBLUen0/vKPxf6pw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2", + "regexpu-core": "^4.6.0" + } + }, + "node_modules/css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-tree/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/css-unit-converter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.1.tgz", + "integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=", + "dev": true + }, + "node_modules/css-what": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz", + "integrity": "sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/css/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/cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", + "dev": true, + "dependencies": { + "through": "X.X.X" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", + "dev": true, + "dependencies": { + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.7", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-preset-default": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", + "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", + "dev": true, + "dependencies": { + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.2", + "postcss-unique-selectors": "^4.0.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/csso": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.0.3.tgz", + "integrity": "sha512-NL3spysxUkcrOgnpsT4Xdl2aiEiBG6bXswAABQVHcMrfjjBisFOKwLDOmf4wf32aPdcJws1zds2B0Rg+jqMyHQ==", + "dev": true, + "dependencies": { + "css-tree": "1.0.0-alpha.39" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "1.0.0-alpha.39", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.39.tgz", + "integrity": "sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.6", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.6.tgz", + "integrity": "sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA==", + "dev": true + }, + "node_modules/csso/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/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "node_modules/cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", + "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==", + "dev": true + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/date-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", + "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dependencies": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "dev": true, + "dependencies": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "dependencies": { + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/defaults/node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "node_modules/del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "dependencies": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/del/node_modules/globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/globby/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/del/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", + "optional": true + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/dependency-graph": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.7.2.tgz", + "integrity": "sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "node_modules/detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "dev": true + }, + "node_modules/detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "dev": true, + "dependencies": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + }, + "bin": { + "detective": "bin/detective.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/dezalgo": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", + "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "dev": true, + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "dependencies": { + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "node_modules/dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "dependencies": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "dependencies": { + "buffer-indexof": "^1.0.0" + } + }, + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "node_modules/dom-serializer/node_modules/domelementtype": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", + "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==", + "dev": true + }, + "node_modules/domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true, + "engines": { + "node": ">=0.4", + "npm": ">=1.2" + } + }, + "node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "node_modules/domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/dot-prop": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", + "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.3.427", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.427.tgz", + "integrity": "sha512-/rG5G7Opcw68/Yrb4qYkz07h3bESVRJjUl4X/FrKLXzoUJleKm6D7K7rTTz8V5LUWnd+BbTOyxJX2XprRqHD8A==", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "dev": true, + "dependencies": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "dev": true, + "dependencies": { + "iconv-lite": "~0.4.13" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/engine.io": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", + "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + } + }, + "node_modules/engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "dev": true, + "dependencies": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + } + }, + "node_modules/engine.io-client/node_modules/component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "node_modules/engine.io-client/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/engine.io-client/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "node_modules/engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "dependencies": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/engine.io/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/engine.io/node_modules/ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz", + "integrity": "sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "node_modules/entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", + "dev": true + }, + "node_modules/err-code": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=", + "dev": true + }, + "node_modules/errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dependencies": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "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/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "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": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "dependencies": { + "estraverse": "^4.1.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", + "integrity": "sha1-teEHm1n7XhuidxwKmTvgYKWMmbo=" + }, + "node_modules/events": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", + "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/eventsource": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", + "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "dev": true, + "dependencies": { + "original": "^1.0.0" + }, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/express/node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + }, + "node_modules/fast-diff": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz", + "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==" + }, + "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/fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "node_modules/faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", + "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-loader": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.0.0.tgz", + "integrity": "sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "node_modules/fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "dependencies": { + "glob": "^7.0.3", + "minimatch": "^3.0.3" + } + }, + "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/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-cache-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-cache-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-cache-dir/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-cache-dir/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/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/find-cache-dir/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/follow-redirects": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz", + "integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==", + "dev": true, + "dependencies": { + "debug": "^3.0.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/follow-redirects/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/fs-extra": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", + "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "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==" + }, + "node_modules/genfun": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", + "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz", + "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==", + "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": "*" + } + }, + "node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "optional": true, + "dependencies": { + "delegate": "^3.1.2" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dev": true, + "dependencies": { + "isarray": "2.0.1" + } + }, + "node_modules/has-binary2/node_modules/isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + }, + "node_modules/has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/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/hash-base/node_modules/safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", + "dev": true + }, + "node_modules/highlight.js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.0.1.tgz", + "integrity": "sha512-l1HB5S9nmBuvurFIOPbpeJv4psKh2MyKCTOYRK/E6dwRXkbG96PLH7amP/xpGNyZOK8OWqv45DxLS/ZAIb3n9w==", + "deprecated": "Potential security issue. Upgrade to @latest", + "engines": { + "node": "*" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hosted-git-info": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.4.tgz", + "integrity": "sha512-4oT62d2jwSDBbLLFLZE+1vPuQ1h8p9wjrJ8Mqx5TjsyWmBMV5B13eJqn8pvluqubLf3cJPTfiYCIwNwDNmzScQ==", + "dev": true, + "dependencies": { + "lru-cache": "^5.1.1" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", + "dev": true + }, + "node_modules/hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", + "dev": true + }, + "node_modules/html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "dev": true + }, + "node_modules/html-entities": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz", + "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==", + "dev": true + }, + "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-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/http-parser-js": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", + "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "dependencies": { + "agent-base": "4", + "debug": "3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dev": true, + "dependencies": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/http-proxy/node_modules/eventemitter3": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", + "dev": true + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/humanize-duration": { + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.24.0.tgz", + "integrity": "sha512-B3udnqisaDeRsvUSb+5n2hjxhABI9jotB+i1IEhgHhguTeM5LxIUKoVIu7UpeyaPOygr/Fnv7UhOi45kYYG+tg==" + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.14" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "node_modules/iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "node_modules/ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "node_modules/ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, + "node_modules/import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "dependencies": { + "import-from": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dev": true, + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "dependencies": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "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/indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "node_modules/indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "deprecated": "Please update to ini >=1.3.6 to avoid a prototype pollution issue", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/inquirer": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", + "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "dependencies": { + "@types/color-name": "^1.1.1", + "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": "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/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/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/inquirer/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dev": true, + "dependencies": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "node_modules/ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", + "dev": true, + "dependencies": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" + } + }, + "node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-docker": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.0.0.tgz", + "integrity": "sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dev": true, + "dependencies": { + "is-path-inside": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "dependencies": { + "path-is-inside": "^1.0.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dependencies": { + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-svg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "dev": true, + "dependencies": { + "html-comment-regex": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isbinaryfile": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.6.tgz", + "integrity": "sha512-ORrEy+SNVqUhrCaal4hA4fBzhggQQ+BaLntyPOdoEiwlKZW9BZiJXjg3RMiruE4tPEI3pyVPpySHQF/dKWperg==", + "dev": true, + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "node_modules/istanbul-api": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.6.tgz", + "integrity": "sha512-x0Eicp6KsShG1k1rMgBAi/1GgY7kFGEBwQpw3PXGEmu+rBcBNhqU8g2DgY9mlepAsLPzrzrbqSgCGANnki4POA==", + "dev": true, + "dependencies": { + "async": "^2.6.2", + "compare-versions": "^3.4.0", + "fileset": "^2.0.3", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-hook": "^2.0.7", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.4", + "js-yaml": "^3.13.1", + "make-dir": "^2.1.0", + "minimatch": "^3.0.4", + "once": "^1.4.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-api/node_modules/istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-api/node_modules/istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-hook": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", + "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", + "dev": true, + "dependencies": { + "append-transform": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz", + "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.5", + "@babel/parser": "^7.7.5", + "@babel/template": "^7.7.4", + "@babel/traverse": "^7.7.4", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-report/node_modules/istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/istanbul-lib-source-maps/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/istanbul-reports": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jasmine": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", + "dev": true, + "dependencies": { + "exit": "^0.1.2", + "glob": "^7.0.6", + "jasmine-core": "~2.8.0" + }, + "bin": { + "jasmine": "bin/jasmine.js" + } + }, + "node_modules/jasmine-core": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.5.0.tgz", + "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==", + "dev": true + }, + "node_modules/jasmine-spec-reporter": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz", + "integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==", + "dev": true, + "dependencies": { + "colors": "1.1.2" + } + }, + "node_modules/jasmine/node_modules/jasmine-core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", + "dev": true + }, + "node_modules/jasminewd2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", + "dev": true, + "engines": { + "node": ">= 6.9.x" + } + }, + "node_modules/jest-worker": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.1.0.tgz", + "integrity": "sha512-ZHhHtlxOWSxCoNOKHGbiLzXnl42ga9CxDr27H36Qn+15pQZd3R/F24jrmjDelw9j/iHUIWMWs08/u2QN50HHOg==", + "dev": true, + "dependencies": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 8.3" + } + }, + "node_modules/jest-worker/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-worker/node_modules/supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "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-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "node_modules/json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", + "dev": true + }, + "node_modules/json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/jszip": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.4.0.tgz", + "integrity": "sha512-gZAOYuPl4EhPTXT0GjhI3o+ZAz3su6EhLrKUoAivcKqyqC7laS5JEv4XWZND9BgcDcF83vI85yGbDmDR6UhrIg==", + "dev": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" + } + }, + "node_modules/karma": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/karma/-/karma-5.0.4.tgz", + "integrity": "sha512-UGqTe2LBiGQBXRN+Fygeiq63tbfOX45639SKSbPkLpARwnxROWJZg+froGkpHxr84FXCe8UGCf+1PITM6frT5w==", + "dev": true, + "dependencies": { + "body-parser": "^1.16.1", + "braces": "^3.0.2", + "chokidar": "^3.0.0", + "colors": "^1.1.0", + "connect": "^3.6.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.0", + "flatted": "^2.0.0", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^4.0.2", + "lodash": "^4.17.14", + "log4js": "^4.0.0", + "mime": "^2.3.1", + "minimatch": "^3.0.2", + "qjobs": "^1.1.4", + "range-parser": "^1.2.0", + "rimraf": "^2.6.0", + "socket.io": "2.1.1", + "source-map": "^0.6.1", + "tmp": "0.0.33", + "ua-parser-js": "0.7.21", + "yargs": "^15.3.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz", + "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==", + "dev": true, + "dependencies": { + "which": "^1.2.1" + } + }, + "node_modules/karma-coverage-istanbul-reporter": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.1.1.tgz", + "integrity": "sha512-CH8lTi8+kKXGvrhy94+EkEMldLCiUA0xMOiL31vvli9qK0T+qcXJAwWBRVJWnVWxYkTmyWar8lPz63dxX6/z1A==", + "dev": true, + "dependencies": { + "istanbul-api": "^2.1.6", + "minimatch": "^3.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/mattlewis92" + } + }, + "node_modules/karma-jasmine": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-3.0.3.tgz", + "integrity": "sha512-80iBR8/hLFY2Uw3S2GG6EndWtMCGMJjrCYNwYROWsJFVTjWrRSsLqcA2ye+U3ygW5sjOQo8f+78L8cGUxjC/+A==", + "dev": true, + "dependencies": { + "jasmine-core": "^3.5.0" + }, + "engines": { + "node": ">= 8" + }, + "peerDependencies": { + "karma": "*" + } + }, + "node_modules/karma-jasmine-html-reporter": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.5.3.tgz", + "integrity": "sha512-ci0VrjuCaFj+9d1tYlTE3KIPUCp0rz874zWWU3JgCMqGIyw5ke+BXWFPOAGAqUdCJcrMwneyvp1zFXA74MiPUA==", + "dev": true, + "peerDependencies": { + "jasmine-core": ">=3.5", + "karma": ">=0.9", + "karma-jasmine": ">=1.1" + } + }, + "node_modules/karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "dependencies": { + "source-map-support": "^0.5.5" + } + }, + "node_modules/karma/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "dependencies": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/karma/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/karma/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/karma/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/karma/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/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/karma/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/karma/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/mime": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz", + "integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/karma/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/karma/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/karma/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/karma/node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/karma/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/karma/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/karma/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/yargs": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", + "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/katex": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.11.1.tgz", + "integrity": "sha512-5oANDICCTX0NqYIyAiFCCwjQ7ERu3DQG2JFHLbYOf+fXaMoH8eg/zOq5WSYJsKMi/QebW+Eh3gSM+oss1H/bww==", + "dependencies": { + "commander": "^2.19.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "dependencies": { + "invert-kv": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/less/-/less-3.11.1.tgz", + "integrity": "sha512-tlWX341RECuTOvoDIvtFqXsKj072hm3+9ymRBe76/mD6O5ZZecnlAOVDlWAleF2+aohFrxNidXhv2773f6kY7g==", + "dev": true, + "dependencies": { + "clone": "^2.1.2", + "tslib": "^1.10.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "mime": "^1.4.1", + "mkdirp": "^0.5.0", + "promise": "^7.1.1", + "request": "^2.83.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-5.0.0.tgz", + "integrity": "sha512-bquCU89mO/yWLaUq0Clk7qCsKhsF/TZpJUzETRvJa9KSVEL9SO3ovCvdEHISBhrC81OwC8QSVX7E0bzElZj9cg==", + "dev": true, + "dependencies": { + "clone": "^2.1.1", + "loader-utils": "^1.1.0", + "pify": "^4.0.1" + }, + "engines": { + "node": ">= 4.8.0" + }, + "peerDependencies": { + "less": "^2.3.1 || ^3.0.0", + "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0" + } + }, + "node_modules/less-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/less-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/less/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, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "dev": true, + "dependencies": { + "leven": "^3.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/license-webpack-plugin": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-2.1.4.tgz", + "integrity": "sha512-1Xq72fmPbTg5KofXs+yI5L4QqPFjQ6mZxoeI6D7gfiEDOtaEIk6PGrdLaej90bpDqKNHNxlQ/MW4tMAL6xMPJQ==", + "dev": true, + "dependencies": { + "@types/webpack-sources": "^0.1.5", + "webpack-sources": "^1.2.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true, + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "node_modules/lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=", + "dev": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "node_modules/log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log4js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.5.1.tgz", + "integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==", + "dev": true, + "dependencies": { + "date-format": "^2.0.0", + "debug": "^4.1.1", + "flatted": "^2.0.0", + "rfdc": "^1.1.4", + "streamroller": "^1.0.6" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/loglevel": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.8.tgz", + "integrity": "sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-loglevel?utm_medium=referral&utm_source=npm_fund" + } + }, + "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/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/lru-cache/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/luxon": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.23.0.tgz", + "integrity": "sha512-+6a/bXsCWrrR8vfbL41iM92es12zwV2Rum/KPkT+ubOZnnU3Sqbqok/FmD1xsWlWN2Y9Hu0fU/vNgU24ns7bpA==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.4" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-fetch-happen": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz", + "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==", + "dev": true, + "dependencies": { + "agentkeepalive": "^3.4.1", + "cacache": "^12.0.0", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/make-fetch-happen/node_modules/ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "dependencies": { + "figgy-pudding": "^3.5.1" + } + }, + "node_modules/mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "dev": true + }, + "node_modules/map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "dependencies": { + "p-defer": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/marked": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz", + "integrity": "sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==", + "bin": { + "marked": "bin/marked" + }, + "engines": { + "node": ">= 8.16.2" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "dev": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "dependencies": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "node_modules/merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/merge-source-map/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/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/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/micromatch/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dev": true, + "dependencies": { + "mime-db": "1.44.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz", + "integrity": "sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A==", + "dev": true, + "dependencies": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.4.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "dependencies": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/minipass": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.1.tgz", + "integrity": "sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.2.tgz", + "integrity": "sha512-3JS5A2DKhD2g0Gg8x3yamO0pj7YeKGwVlDS90pF++kxptwx/F+B//roxf9SqYil5tQo65bijy+dAuAFZmYOouA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.0.tgz", + "integrity": "sha512-EzTZN/fjSvifSX0SlqUERCN39o6T40AMarPbv0MrarSFtIITCBh7bi+dU8nxGFHuqs9jdIAeoYoKuQAAASsPPA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "dependencies": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", + "engines": { + "node": "*" + } + }, + "node_modules/move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "dependencies": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "node_modules/move-concurrently/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "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/multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "dependencies": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "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/nan": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", + "dev": true, + "optional": true + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "node_modules/ng-apexcharts": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/ng-apexcharts/-/ng-apexcharts-1.2.3.tgz", + "integrity": "sha512-4G+JRCWp8uSSBJKvYP9vKHEZIC0w6YuRLasumZS35fCCc7bzLY+L907n8khG9Xeoo4LBt7pVbmjb9P+lSWs/5g==", + "dependencies": { + "tslib": "^1.9.0" + }, + "peerDependencies": { + "@angular/common": "^8.0.0", + "@angular/core": "^8.0.0", + "apexcharts": "^3.11.2", + "rxjs": "^6.4.0" + } + }, + "node_modules/ngx-markdown": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-9.0.0.tgz", + "integrity": "sha512-wcXMxA4Skgk9SzhfDRjihap/Kjq17jmMQiE/Ccp0bNibGaDgS5DbZiPBlMNLkp669UvjY9wVuxE4NuDtmQHS9w==", + "dependencies": { + "@types/marked": "^0.7.2", + "katex": "^0.11.0", + "marked": "^0.8.0", + "prismjs": "^1.16.0" + }, + "peerDependencies": { + "@angular/common": "^8.0.0 || ^9.0.0", + "@angular/core": "^8.0.0 || ^9.0.0", + "@angular/platform-browser": "^8.0.0 || ^9.0.0", + "rxjs": "^6.0.0", + "tslib": "^1.10.0", + "zone.js": "^0.9.0 || ^0.10.0" + } + }, + "node_modules/ngx-quill": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/ngx-quill/-/ngx-quill-9.1.0.tgz", + "integrity": "sha512-3VkacaTNGP3akHpjmxT+mvhfM/YeDsuQCwZWI1kKvB66BKSIaiZJOM8E9MHV++QOHSQ0nJzU6TUgYgxaAaSj0g==", + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "@angular/animations": "^7.0.0 || ^8.0.0 || ^9.0.0", + "@angular/common": "^7.0.0 || ^8.0.0 || ^9.0.0", + "@angular/core": "^7.0.0 || ^8.0.0 || ^9.0.0", + "@angular/forms": "^7.0.0 || ^8.0.0 || ^9.0.0", + "@angular/platform-browser": "^7.0.0 || ^8.0.0 || ^9.0.0", + "quill": "^1.3.7", + "rxjs": "^6.4.0 || ^6.5.0", + "tslib": "^1.10.0" + } + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/node-emoji": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", + "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", + "dev": true, + "dependencies": { + "lodash.toarray": "^4.4.0" + } + }, + "node_modules/node-fetch-npm": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.4.tgz", + "integrity": "sha512-iOuIQDWDyjhv9qSDrj9aq/klt6F9z1p2otB3AV7v3zBDcL/x+OfGsvGQZZCcMZbUf4Ujw1xGNQkjvGnVT22cKg==", + "dev": true, + "dependencies": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/node-forge": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", + "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==", + "dev": true, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "dependencies": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + } + }, + "node_modules/node-libs-browser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "node_modules/node-releases": { + "version": "1.1.53", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.53.tgz", + "integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize.css": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz", + "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==", + "dev": true + }, + "node_modules/npm-bundled": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-install-checks": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz", + "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-install-checks/node_modules/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "node_modules/npm-package-arg": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.0.1.tgz", + "integrity": "sha512-/h5Fm6a/exByzFSTm7jAyHbgOqErl9qSNJDQF32Si/ZzgwT2TERVxRxn3Jurw1wflgyVVAxnFR4fRHPM7y1ClQ==", + "dev": true, + "dependencies": { + "hosted-git-info": "^3.0.2", + "semver": "^7.0.0", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-package-arg/node_modules/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "dev": true, + "dependencies": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-pick-manifest": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.0.0.tgz", + "integrity": "sha512-PdJpXMvjqt4nftNEDpCgjBUF8yI3Q3MyuAmVB9nemnnCg32F4BPL/JFBfdj8DubgHCYUFQhtLWmBPvdsFtjWMg==", + "dev": true, + "dependencies": { + "npm-install-checks": "^4.0.0", + "npm-package-arg": "^8.0.0", + "semver": "^7.0.0" + } + }, + "node_modules/npm-pick-manifest/node_modules/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-registry-fetch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.4.tgz", + "integrity": "sha512-6jb34hX/iYNQebqWUHtU8YF6Cjb1H6ouTFPClYsyiW6lpFkljTpdeftm53rRojtja1rKAvKNIIiTS5Sjpw4wsA==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "JSONStream": "^1.3.4", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "npm-package-arg": "^6.1.0", + "safe-buffer": "^5.2.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "node_modules/npm-registry-fetch/node_modules/npm-package-arg": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.7.1", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + }, + "node_modules/npm-registry-fetch/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.2.tgz", + "integrity": "sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ==", + "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==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dependencies": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/open": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/open/-/open-7.0.3.tgz", + "integrity": "sha512-sP2ru2v0P290WFfv49Ap8MF6PkzGNnGlAwHweB4WR4mr5d2d0woiCluUeJ218w7/+PmoBy9JmYgD5A4mLcWOFA==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "dependencies": { + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/opn/node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ora": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/ora/-/ora-4.0.3.tgz", + "integrity": "sha512-fnDebVFyz309A73cqCipVL1fBZewq4vwgSHfxh43vVy31mbyoQ8sCH3Oeaog/owYOs/lLlGVPCISQonTneg6Pg==", + "dev": true, + "dependencies": { + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.2.0", + "is-interactive": "^1.0.0", + "log-symbols": "^3.0.0", + "mute-stream": "0.0.8", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "dependencies": { + "@types/color-name": "^1.1.1", + "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": "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/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/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "dependencies": { + "url-parse": "^1.4.3" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "dependencies": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "dev": true, + "dependencies": { + "retry": "^0.12.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pacote": { + "version": "9.5.12", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.12.tgz", + "integrity": "sha512-BUIj/4kKbwWg4RtnBncXPJd15piFSVNpTzY0rysSr3VnMowTYgkGKcaHrbReepAkjTr8lH2CVWRi58Spg2CicQ==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.3", + "cacache": "^12.0.2", + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.1.0", + "glob": "^7.1.3", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "minimatch": "^3.0.4", + "minipass": "^2.3.5", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-normalize-package-bin": "^1.0.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.12", + "npm-pick-manifest": "^3.0.0", + "npm-registry-fetch": "^4.0.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.1", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.6.0", + "ssri": "^6.0.1", + "tar": "^4.4.10", + "unique-filename": "^1.1.1", + "which": "^1.3.1" + } + }, + "node_modules/pacote/node_modules/cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "node_modules/pacote/node_modules/fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/pacote/node_modules/hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "node_modules/pacote/node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/pacote/node_modules/minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/pacote/node_modules/npm-package-arg": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.7.1", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "node_modules/pacote/node_modules/npm-pick-manifest": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz", + "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==", + "dev": true, + "dependencies": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, + "node_modules/pacote/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/pacote/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/pacote/node_modules/ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "dependencies": { + "figgy-pudding": "^3.5.1" + } + }, + "node_modules/pacote/node_modules/tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/pacote/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/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "dependencies": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "node_modules/parchment": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz", + "integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==" + }, + "node_modules/parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "dependencies": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "optional": true + }, + "node_modules/parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "dependencies": { + "better-assert": "~1.0.0" + } + }, + "node_modules/parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "dependencies": { + "better-assert": "~1.0.0" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-type/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/perfect-scrollbar": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.0.tgz", + "integrity": "sha512-NrNHJn5mUGupSiheBTy6x+6SXCFbLlm8fVZh9moIzw/LgqElN5q4ncR4pbCBCYuCJ8Kcl9mYM0NgDxvW+b4LxA==" + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-dir/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/portfinder": { + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.26.tgz", + "integrity": "sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ==", + "dev": true, + "dependencies": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/portfinder/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + }, + "node_modules/postcss-calc": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.2.tgz", + "integrity": "sha512-rofZFHUg6ZIrvRwPeFktv06GdbDYLcGqh9EwiMutZg+a0oePCCw1zHOEiji6LCpyRcjTREtPASuUqeAvYlEVvQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-colormin/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-convert-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-discard-comments": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-functions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-functions/-/postcss-functions-3.0.0.tgz", + "integrity": "sha1-DpTQFERwCkgd4g3k1V+yZAVkJQ4=", + "dev": true, + "dependencies": { + "glob": "^7.1.2", + "object-assign": "^4.1.1", + "postcss": "^6.0.9", + "postcss-value-parser": "^3.3.0" + } + }, + "node_modules/postcss-functions/node_modules/postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "dependencies": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss-functions/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-functions/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/postcss-import": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-12.0.1.tgz", + "integrity": "sha512-3Gti33dmCjyKBgimqGxL3vcV8w9+bsHwO5UrBawp796+jdardbcFl4RP5w/76BwNL7aGzpKstIfF9I+kdE8pTw==", + "dev": true, + "dependencies": { + "postcss": "^7.0.1", + "postcss-value-parser": "^3.2.3", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss-import/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-2.0.3.tgz", + "integrity": "sha512-zS59pAk3deu6dVHyrGqmC3oDXBdNdajk4k1RyxeVXCrcEDBUBHoIhE4QTsmhxgzXxsaqFDAkUZfmMa5f/N/79w==", + "dev": true, + "dependencies": { + "camelcase-css": "^2.0.1", + "postcss": "^7.0.18" + } + }, + "node_modules/postcss-load-config": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz", + "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==", + "dev": true, + "dependencies": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "dev": true, + "dependencies": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/postcss-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss-loader/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "dev": true, + "dependencies": { + "css-color-names": "0.0.4", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-merge-longhand/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-merge-rules": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-merge-rules/node_modules/postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "dependencies": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-font-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-minify-gradients": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "dev": true, + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-gradients/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "dev": true, + "dependencies": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-params/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "dev": true, + "dependencies": { + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "dependencies": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz", + "integrity": "sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ==", + "dev": true, + "dependencies": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.16", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-values": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", + "dev": true, + "dependencies": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + } + }, + "node_modules/postcss-nested": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-4.2.1.tgz", + "integrity": "sha512-AMayXX8tS0HCp4O4lolp4ygj9wBn32DJWXvG6gCv+ZvJrEa00GUxJcJEEzMh87BIe6FrWdYkpR2cuyqHKrxmXw==", + "dev": true, + "dependencies": { + "postcss": "^7.0.21", + "postcss-selector-parser": "^6.0.2" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "dev": true, + "dependencies": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-display-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "dev": true, + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-positions/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "dev": true, + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-repeat-style/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "dev": true, + "dependencies": { + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-string/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "dev": true, + "dependencies": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-timing-functions/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-unicode/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "dev": true, + "dependencies": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-url/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-normalize-whitespace/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "dev": true, + "dependencies": { + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-ordered-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "dev": true, + "dependencies": { + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-reduce-transforms/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz", + "integrity": "sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", + "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", + "dev": true, + "dependencies": { + "is-svg": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-svgo/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "dev": true, + "dependencies": { + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "node_modules/postcss/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/postcss/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/prismjs": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.20.0.tgz", + "integrity": "sha512-AEDjSrVNkynnw6A+B1DsFkd6AVdTnp+/WoUixFRULlCLZVRZlVQMVWio/16jv7G1FscUxQxOQhWwApgbnxr6kQ==", + "optionalDependencies": { + "clipboard": "^2.0.0" + } + }, + "node_modules/private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true, + "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 + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "optional": true, + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "node_modules/promise-retry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", + "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "dev": true, + "dependencies": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/promise-retry/node_modules/retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/protoduck": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", + "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", + "dev": true, + "dependencies": { + "genfun": "^5.0.0" + } + }, + "node_modules/protractor": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.4.4.tgz", + "integrity": "sha512-BaL4vePgu3Vfa/whvTUAlgaCAId4uNSGxIFSCXMgj7LMYENPWLp85h5RBi9pdpX/bWQ8SF6flP7afmi2TC4eHw==", + "dev": true, + "dependencies": { + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "^3.0.0", + "blocking-proxy": "^1.0.0", + "browserstack": "^1.5.1", + "chalk": "^1.1.3", + "glob": "^7.0.3", + "jasmine": "2.8.0", + "jasminewd2": "^2.1.0", + "q": "1.4.1", + "saucelabs": "^1.5.0", + "selenium-webdriver": "3.6.0", + "source-map-support": "~0.4.0", + "webdriver-js-extender": "2.1.0", + "webdriver-manager": "^12.0.6", + "yargs": "^12.0.5" + }, + "bin": { + "protractor": "bin/protractor", + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/protractor/node_modules/@types/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "dev": true + }, + "node_modules/protractor/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "dependencies": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "dependencies": { + "is-path-inside": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "dependencies": { + "path-is-inside": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/protractor/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/protractor/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/protractor/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/protractor/node_modules/source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "dependencies": { + "source-map": "^0.5.6" + } + }, + "node_modules/protractor/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/protractor/node_modules/webdriver-manager": { + "version": "12.1.7", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.7.tgz", + "integrity": "sha512-XINj6b8CYuUYC93SG3xPkxlyUc3IJbD6Vvo75CVGuG9uzsefDzWQrhz0Lq8vbPxtb4d63CZdYophF8k8Or/YiA==", + "dev": true, + "dependencies": { + "adm-zip": "^0.4.9", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.87.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + }, + "bin": { + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dev": true, + "dependencies": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/pumpify/node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/purgecss": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-2.1.2.tgz", + "integrity": "sha512-5oDBxiT9VonwKmEMohPFRFZrj8fdSVKxHPwq7G5Rx/2pXicZFJu+D4m5bb3NuV0sSK3ooNxq5jFIwwHzifP5FA==", + "dev": true, + "dependencies": { + "commander": "^5.0.0", + "glob": "^7.0.0", + "postcss": "7.0.27", + "postcss-selector-parser": "^6.0.2" + }, + "bin": { + "purgecss": "bin/purgecss" + } + }, + "node_modules/purgecss/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true, + "engines": { + "node": ">=0.9" + } + }, + "node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "dependencies": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", + "dev": true + }, + "node_modules/quill": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/quill/-/quill-1.3.7.tgz", + "integrity": "sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==", + "dependencies": { + "clone": "^2.1.1", + "deep-equal": "^1.0.1", + "eventemitter3": "^2.0.3", + "extend": "^3.0.2", + "parchment": "^1.1.4", + "quill-delta": "^3.6.2" + } + }, + "node_modules/quill-delta": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz", + "integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==", + "dependencies": { + "deep-equal": "^1.0.1", + "extend": "^3.0.2", + "fast-diff": "1.1.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.0.tgz", + "integrity": "sha512-iINUOYvl1cGEmfoaLjnZXt4bKfT2LJnZZib5N/LLyAphC+Dd11vNP9CNVb38j+SAJpFI1uo8j9frmih53ASy7Q==", + "dev": true, + "dependencies": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.5.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/raw-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/raw-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-cache/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-package-json": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz", + "integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==", + "dev": true, + "dependencies": { + "glob": "^7.1.1", + "json-parse-better-errors": "^1.0.1", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.2" + } + }, + "node_modules/read-package-tree": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", + "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", + "dev": true, + "dependencies": { + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.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, + "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/readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "dev": true, + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reduce-css-calc": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.7.tgz", + "integrity": "sha512-fDnlZ+AybAS3C7Q9xDq5y8A2z+lT63zLbynew/lur/IR24OQF5x98tfNwf79mzEdfywZ0a2wpM860FhFfMxZlA==", + "dev": true, + "dependencies": { + "css-unit-converter": "^1.1.1", + "postcss-value-parser": "^3.3.0" + } + }, + "node_modules/reduce-css-calc/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "node_modules/regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.4.tgz", + "integrity": "sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4", + "private": "^0.1.8" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz", + "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", + "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "node_modules/repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "dev": true + }, + "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/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/rfdc": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", + "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==", + "dev": true + }, + "node_modules/rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", + "dev": true + }, + "node_modules/rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", + "dev": true + }, + "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/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rollup": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.1.0.tgz", + "integrity": "sha512-gfE1455AEazVVTJoeQtcOq/U6GSxwoj4XPSWVsuWmgIxj7sBQNLDOSA82PbdMe+cP8ql8fR1jogPFe8Wg8g4SQ==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.2" + } + }, + "node_modules/rrule": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.6.4.tgz", + "integrity": "sha512-sLdnh4lmjUqq8liFiOUXD5kWp/FcnbDLPwq5YAc/RrN6120XOPb86Ae5zxF7ttBVq8O3LxjjORMEit1baluahA==", + "dependencies": { + "tslib": "^1.10.0" + }, + "optionalDependencies": { + "luxon": "^1.21.3" + } + }, + "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-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "dependencies": { + "aproba": "^1.1.1" + } + }, + "node_modules/rxjs": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", + "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.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-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "dependencies": { + "ret": "~0.1.10" + } + }, + "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/sass": { + "version": "1.26.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.26.3.tgz", + "integrity": "sha512-5NMHI1+YFYw4sN3yfKjpLuV9B5l7MqQ6FlkTcC4FT+oHbBRUZoSjHrrt/mE0nFXJyY2kQtU9ou9HxvFVjLFuuw==", + "dev": true, + "dependencies": { + "chokidar": ">=2.0.0 <4.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/sass-loader": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.2.tgz", + "integrity": "sha512-7o4dbSK8/Ol2KflEmSco4jTjQoV988bM82P9CZdmo9hR3RLnvNc0ufMNdMrB0caq38JQ/FgF4/7RcbcfKzxoFQ==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.2.3", + "neo-async": "^2.6.1", + "schema-utils": "^2.6.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0", + "sass": "^1.3.0", + "webpack": "^4.36.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/sass-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/sass-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/saucelabs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", + "dev": true, + "dependencies": { + "https-proxy-agent": "^2.2.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/schema-utils": { + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.6.tgz", + "integrity": "sha512-wHutF/WPSbIi9x6ctjGGk2Hvl0VOz5l3EKEuKbjPlB30mKZUzb9A5k9yEXRX3pwyqVLPvpfZZEllaFq/M718hA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", + "optional": true + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "node_modules/selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "dependencies": { + "jszip": "^3.1.3", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" + }, + "engines": { + "node": ">= 6.9.0" + } + }, + "node_modules/selenium-webdriver/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/selenium-webdriver/node_modules/tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/selfsigned": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz", + "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==", + "dev": true, + "dependencies": { + "node-forge": "0.9.0" + } + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/semver-dsl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", + "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", + "dev": true, + "dependencies": { + "semver": "^5.3.0" + } + }, + "node_modules/semver-dsl/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-intersect": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz", + "integrity": "sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ==", + "dev": true, + "dependencies": { + "semver": "^5.0.0" + } + }, + "node_modules/semver-intersect/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "dev": true + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dev": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + }, + "node_modules/slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/smart-buffer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", + "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "dev": true, + "dependencies": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", + "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==", + "dev": true + }, + "node_modules/socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "dev": true, + "dependencies": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + } + }, + "node_modules/socket.io-client/node_modules/component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "node_modules/socket.io-client/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/socket.io-client/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "dev": true, + "dependencies": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + } + }, + "node_modules/socket.io-parser/node_modules/component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + }, + "node_modules/socket.io-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/socket.io/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/socket.io/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/sockjs": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" + } + }, + "node_modules/sockjs-client": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz", + "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==", + "dev": true, + "dependencies": { + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" + } + }, + "node_modules/sockjs-client/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/sockjs-client/node_modules/faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/socks": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", + "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", + "dev": true, + "dependencies": { + "ip": "1.1.5", + "smart-buffer": "^4.1.0" + }, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", + "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "dev": true, + "dependencies": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-loader": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-0.2.4.tgz", + "integrity": "sha512-OU6UJUty+i2JDpTItnizPrlpOIBLmQbWMuBg9q5bVtnHACqw1tn9nNwqJLbv0/00JjnJb/Ee5g5WS5vrRv7zIQ==", + "dev": true, + "dependencies": { + "async": "^2.5.0", + "loader-utils": "^1.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/source-map-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/source-map-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/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-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/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/speed-measure-webpack-plugin": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.3.1.tgz", + "integrity": "sha512-qVIkJvbtS9j/UeZumbdfz0vg+QfG/zxonAjzefZrqzkr7xOncLVXkeGbTpzd1gjCBM4PmVNkWlkeTVhgskAGSQ==", + "dev": true, + "dependencies": { + "chalk": "^2.0.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "webpack": "^1 || ^2 || ^3 || ^4" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssri": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.0.tgz", + "integrity": "sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "node_modules/streamroller": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.6.tgz", + "integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==", + "dev": true, + "dependencies": { + "async": "^2.6.2", + "date-format": "^2.0.0", + "debug": "^3.2.6", + "fs-extra": "^7.0.1", + "lodash": "^4.17.14" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/streamroller/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/streamroller/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true, + "engines": { + "node": ">=0.10.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": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.0.tgz", + "integrity": "sha512-EEJnGqa/xNfIg05SxiPSqRS7S9qwDhYts1TSLR1BQfYUfPe1stofgGKvwERK9+9yf+PpfBMlpBaCHucXGPQfUA==", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.0.tgz", + "integrity": "sha512-iCP8g01NFYiiBOnwG1Xc3WZLyoo+RuBymwIlWncShXDDJYWN6DbnM3odslBJdgCdRlq94B5s63NWAZlcn2CS4w==", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/style-loader": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.1.3.tgz", + "integrity": "sha512-rlkH7X/22yuwFYK357fMN/BxYOorfnfq0eD7+vqlemSK4wEcejFF1dg4zxP0euBW8NrYx2WZzZ8PPFevr7D+Kw==", + "dev": true, + "dependencies": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.6.4" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/style-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/style-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/stylehacks": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/stylehacks/node_modules/postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "dependencies": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stylus": { + "version": "0.54.7", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.7.tgz", + "integrity": "sha512-Yw3WMTzVwevT6ZTrLCYNHAFmanMxdylelL3hkWNgPMeTCpMwpV3nXjpOHuBXtFv7aiO2xRuQS6OoAdgkNcSNug==", + "dev": true, + "dependencies": { + "css-parse": "~2.0.0", + "debug": "~3.1.0", + "glob": "^7.1.3", + "mkdirp": "~0.5.x", + "safer-buffer": "^2.1.2", + "sax": "~1.2.4", + "semver": "^6.0.0", + "source-map": "^0.7.3" + }, + "bin": { + "stylus": "bin/stylus" + }, + "engines": { + "node": "*" + } + }, + "node_modules/stylus-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.2.tgz", + "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==", + "dev": true, + "dependencies": { + "loader-utils": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "when": "~3.6.x" + }, + "peerDependencies": { + "stylus": ">=0.52.4" + } + }, + "node_modules/stylus-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/stylus-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/stylus/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/stylus/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "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/svg.draggable.js": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz", + "integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==", + "dependencies": { + "svg.js": "^2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.easing.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz", + "integrity": "sha1-iqmUawqOJ4V6XEChDrpAkeVpHxI=", + "dependencies": { + "svg.js": ">=2.3.x" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.filter.js": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz", + "integrity": "sha1-kQCOFROJ3ZIwd5/L5uLJo2LRwgM=", + "dependencies": { + "svg.js": "^2.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.js": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz", + "integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==" + }, + "node_modules/svg.pathmorphing.js": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz", + "integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==", + "dependencies": { + "svg.js": "^2.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.resize.js": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz", + "integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==", + "dependencies": { + "svg.js": "^2.6.5", + "svg.select.js": "^2.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.resize.js/node_modules/svg.select.js": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz", + "integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==", + "dependencies": { + "svg.js": "^2.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.select.js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz", + "integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==", + "dependencies": { + "svg.js": "^2.6.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "dev": true, + "dependencies": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tailwindcss": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.4.4.tgz", + "integrity": "sha512-49Hy/+WnqQhxtGGjcGlhRlE7+hooX2A0/JOeJnA78fCEqDRlhURWujHY05aCl+lJ6G2qQ+1wlQTg4PqMPUcFVA==", + "dev": true, + "dependencies": { + "@fullhuman/postcss-purgecss": "^2.1.2", + "autoprefixer": "^9.4.5", + "browserslist": "^4.12.0", + "bytes": "^3.0.0", + "chalk": "^4.0.0", + "color": "^3.1.2", + "detective": "^5.2.0", + "fs-extra": "^8.0.0", + "lodash": "^4.17.15", + "node-emoji": "^1.8.1", + "normalize.css": "^8.0.1", + "postcss": "^7.0.11", + "postcss-functions": "^3.0.0", + "postcss-js": "^2.0.0", + "postcss-nested": "^4.1.1", + "postcss-selector-parser": "^6.0.0", + "pretty-hrtime": "^1.0.3", + "reduce-css-calc": "^2.1.6", + "resolve": "^1.14.2" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/tailwindcss/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "dependencies": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/tailwindcss/node_modules/chalk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "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/tailwindcss/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/tailwindcss/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/tailwindcss/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/tailwindcss/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/tailwindcss/node_modules/supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.2.tgz", + "integrity": "sha512-Glo3jkRtPcvpDlAs/0+hozav78yoXKFr+c4wgw62NNMO3oo4AaJdCo21Uu7lcwr55h39W2XD1LMERc64wtbItg==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.0", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser": { + "version": "4.6.10", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.10.tgz", + "integrity": "sha512-qbF/3UOo11Hggsbsqm2hPa6+L4w7bkr+09FNseEe8xrcVD3APGLFqE+Oz1ZKAxjYnFsj80rLOfgAtJ0LNJjtTA==", + "dev": true, + "dependencies": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.5.tgz", + "integrity": "sha512-WlWksUoq+E4+JlJ+h+U+QUzXpcsMSSNXkDy9lBVkSqDn1w23Gg29L/ary9GeJVYCGiNJJX7LnVc4bwL1N3/g1w==", + "dev": true, + "dependencies": { + "cacache": "^13.0.1", + "find-cache-dir": "^3.2.0", + "jest-worker": "^25.1.0", + "p-limit": "^2.2.2", + "schema-utils": "^2.6.4", + "serialize-javascript": "^2.1.2", + "source-map": "^0.6.1", + "terser": "^4.4.3", + "webpack-sources": "^1.4.3" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/cacache": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", + "integrity": "sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w==", + "dev": true, + "dependencies": { + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "minipass": "^3.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "p-map": "^3.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^2.7.1", + "ssri": "^7.0.0", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser-webpack-plugin/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser-webpack-plugin/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/terser-webpack-plugin/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/terser-webpack-plugin/node_modules/ssri": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz", + "integrity": "sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g==", + "dev": true, + "dependencies": { + "figgy-pudding": "^3.5.1", + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/terser/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/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/timers-browserify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "dev": true, + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "dev": true + }, + "node_modules/tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "optional": true + }, + "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-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "node_modules/to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "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": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-node": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz", + "integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==", + "dev": true, + "dependencies": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "^3.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" + }, + "peerDependencies": { + "typescript": ">=2.0" + } + }, + "node_modules/tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + }, + "node_modules/tslint": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.2.tgz", + "integrity": "sha512-UyNrLdK3E0fQG/xWNqAFAC5ugtFyPO4JJR1KyyfQAyzR8W0fTRrC91A8Wej4BntFzcvETdCSDa/4PnNYJQLYiA==", + "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.10.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + }, + "peerDependencies": { + "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev" + } + }, + "node_modules/tslint/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "peerDependencies": { + "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" + } + }, + "node_modules/tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "node_modules/type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "node_modules/typescript": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.21", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz", + "integrity": "sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "node_modules/uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/universal-analytics": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/universal-analytics/-/universal-analytics-0.4.20.tgz", + "integrity": "sha512-gE91dtMvNkjO+kWsPstHRtSwHXz0l2axqptGYp5ceg4MsuurloM0PU3pdOfpb5zBXUvyjT4PwhWK2m39uczZuw==", + "dev": true, + "dependencies": { + "debug": "^3.0.0", + "request": "^2.88.0", + "uuid": "^3.0.0" + } + }, + "node_modules/universal-analytics/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "dev": true + }, + "node_modules/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url-parse": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/util-promisify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", + "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", + "dev": true, + "dependencies": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "node_modules/util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "dev": true, + "dependencies": { + "builtins": "^1.0.3" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vendors": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", + "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.1.tgz", + "integrity": "sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA==", + "dev": true, + "dependencies": { + "chokidar": "^2.1.8", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + } + }, + "node_modules/watchpack/node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/watchpack/node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/watchpack/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/fsevents": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.12.tgz", + "integrity": "sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q==", + "bundleDependencies": [ + "node-pre-gyp" + ], + "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1", + "node-pre-gyp": "*" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/abbrev": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/ansi-regex": { + "version": "2.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/aproba": { + "version": "1.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/are-we-there-yet": { + "version": "1.1.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/balanced-match": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/chownr": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/code-point-at": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/console-control-strings": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/core-util-is": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/debug": { + "version": "3.2.6", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/deep-extend": { + "version": "0.6.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/delegates": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/detect-libc": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/fs-minipass": { + "version": "1.2.7", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/gauge": { + "version": "2.7.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/glob": { + "version": "7.1.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": 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/watchpack/node_modules/fsevents/node_modules/has-unicode": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/iconv-lite": { + "version": "0.4.24", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/ignore-walk": { + "version": "3.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/ini": { + "version": "1.3.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/minimatch": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/minimist": { + "version": "1.2.5", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/minipass": { + "version": "2.9.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/minizlib": { + "version": "1.3.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/mkdirp": { + "version": "0.5.3", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/needle": { + "version": "2.3.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/node-pre-gyp": { + "version": "0.14.0", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/nopt": { + "version": "4.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/npm-bundled": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/npm-packlist": { + "version": "1.4.8", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/npmlog": { + "version": "4.1.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/number-is-nan": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/object-assign": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/once": { + "version": "1.4.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/os-homedir": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/os-tmpdir": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/osenv": { + "version": "0.1.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/process-nextick-args": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/rc": { + "version": "1.2.8", + "dev": true, + "inBundle": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/readable-stream": { + "version": "2.3.7", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": 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/watchpack/node_modules/fsevents/node_modules/rimraf": { + "version": "2.7.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/sax": { + "version": "1.2.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/semver": { + "version": "5.7.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/set-blocking": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/signal-exit": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/string-width": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/strip-ansi": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/strip-json-comments": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/tar": { + "version": "4.4.13", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/wide-align": { + "version": "1.1.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/watchpack/node_modules/fsevents/node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/watchpack/node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack/node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/watchpack/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web-animations-js": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/web-animations-js/-/web-animations-js-2.3.2.tgz", + "integrity": "sha512-TOMFWtQdxzjWp8qx4DAraTWTsdhxVSiWa6NkPFSaPtZ1diKUxTn4yTix73A1euG1WbSOMMPcY51cnjTIHrGtDA==" + }, + "node_modules/webdriver-js-extender": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", + "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", + "dev": true, + "dependencies": { + "@types/selenium-webdriver": "^3.0.0", + "selenium-webdriver": "^3.0.1" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/webpack": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.42.0.tgz", + "integrity": "sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz", + "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==", + "dev": true, + "dependencies": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz", + "integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/webpack-dev-server": { + "version": "3.10.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.10.3.tgz", + "integrity": "sha512-e4nWev8YzEVNdOMcNzNeCN947sWJNd43E5XvsJzbAL08kGc2frm1tQ32hTJslRS+H65LCb/AaUCYU7fjHCpDeQ==", + "dev": true, + "dependencies": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.2.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.6", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.25", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.7", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "0.3.19", + "sockjs-client": "1.4.0", + "spdy": "^4.0.1", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "12.0.5" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 6.11.5" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/webpack-dev-server/node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/webpack-dev-server/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.12.tgz", + "integrity": "sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q==", + "bundleDependencies": [ + "node-pre-gyp" + ], + "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1", + "node-pre-gyp": "*" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/abbrev": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/ansi-regex": { + "version": "2.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/aproba": { + "version": "1.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/are-we-there-yet": { + "version": "1.1.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/balanced-match": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/chownr": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/code-point-at": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/console-control-strings": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/core-util-is": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/debug": { + "version": "3.2.6", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/deep-extend": { + "version": "0.6.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/delegates": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/detect-libc": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/fs-minipass": { + "version": "1.2.7", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/gauge": { + "version": "2.7.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/glob": { + "version": "7.1.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": 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/webpack-dev-server/node_modules/fsevents/node_modules/has-unicode": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/iconv-lite": { + "version": "0.4.24", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/ignore-walk": { + "version": "3.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/ini": { + "version": "1.3.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/minimatch": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/minimist": { + "version": "1.2.5", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/minipass": { + "version": "2.9.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/minizlib": { + "version": "1.3.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/mkdirp": { + "version": "0.5.3", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/needle": { + "version": "2.3.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/node-pre-gyp": { + "version": "0.14.0", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/nopt": { + "version": "4.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/npm-bundled": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/npm-packlist": { + "version": "1.4.8", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/npmlog": { + "version": "4.1.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/number-is-nan": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/object-assign": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/once": { + "version": "1.4.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/os-homedir": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/os-tmpdir": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/osenv": { + "version": "0.1.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/process-nextick-args": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/rc": { + "version": "1.2.8", + "dev": true, + "inBundle": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/readable-stream": { + "version": "2.3.7", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": 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/webpack-dev-server/node_modules/fsevents/node_modules/rimraf": { + "version": "2.7.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/sax": { + "version": "1.2.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/semver": { + "version": "5.7.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/set-blocking": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/signal-exit": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/string-width": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/strip-ansi": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/strip-json-comments": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/tar": { + "version": "4.4.13", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/wide-align": { + "version": "1.1.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "optional": true + }, + "node_modules/webpack-dev-server/node_modules/is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-dev-server/node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/webpack-dev-server/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "dependencies": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/webpack-merge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", + "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/webpack-sources/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/webpack-subresource-integrity": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.4.0.tgz", + "integrity": "sha512-GB1kB/LwAWC3CxwcedGhMkxGpNZxSheCe1q+KJP1bakuieAdX/rGHEcf5zsEzhKXpqsGqokgsDoD9dIkr61VDQ==", + "dev": true, + "dependencies": { + "webpack-sources": "^1.3.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "html-webpack-plugin": "^2.21.0 || ~3 || >=4.0.0-alpha.2 <5", + "webpack": "^1.12.11 || ~2 || ~3 || ~4" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "node_modules/webpack/node_modules/cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "node_modules/webpack/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack/node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/webpack/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/webpack/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/webpack/node_modules/memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "node_modules/webpack/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/webpack/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/webpack/node_modules/ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "dependencies": { + "figgy-pudding": "^3.5.1" + } + }, + "node_modules/webpack/node_modules/terser-webpack-plugin": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", + "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", + "dev": true, + "dependencies": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^2.1.2", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", + "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.4.0 <0.4.11", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/when": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", + "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=", + "dev": true + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "dependencies": { + "errno": "~0.1.7" + } + }, + "node_modules/worker-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/worker-plugin/-/worker-plugin-4.0.2.tgz", + "integrity": "sha512-V+1zSZMOOKk+uBzKyNIODLQLsx59zSIOaI75J1EMS0iR1qy+KQR3y/pQ3T0vIhvPfDFapGRMsoMvQNEL3okqSA==", + "dev": true, + "dependencies": { + "loader-utils": "^1.1.0" + }, + "peerDependencies": { + "webpack": ">= 4" + } + }, + "node_modules/worker-plugin/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/worker-plugin/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "dependencies": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "node_modules/yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/yargs/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/zone.js": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz", + "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==" + } + }, "dependencies": { "@angular-devkit/architect": { "version": "0.901.4", @@ -243,7 +18580,8 @@ "@angular/animations": { "version": "9.1.4", "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-9.1.4.tgz", - "integrity": "sha512-gMo/DbCm5BDArladMAeC7/75T2DvhLr4CSUGJt/P/aimTEG2ywoAALs3pzwSSe4qxrHiR0OIksVW3l4km3iXEw==" + "integrity": "sha512-gMo/DbCm5BDArladMAeC7/75T2DvhLr4CSUGJt/P/aimTEG2ywoAALs3pzwSSe4qxrHiR0OIksVW3l4km3iXEw==", + "requires": {} }, "@angular/cdk": { "version": "9.2.2", @@ -304,12 +18642,14 @@ "@angular/common": { "version": "9.1.4", "resolved": "https://registry.npmjs.org/@angular/common/-/common-9.1.4.tgz", - "integrity": "sha512-JvCoCWVbx0tF7l/0WTi24ui/mc2SElyVSNchR4VK/FViARnkvnSBdI/Ef5QWXrsPyKU4PYBtnWWgyxRspH+FBA==" + "integrity": "sha512-JvCoCWVbx0tF7l/0WTi24ui/mc2SElyVSNchR4VK/FViARnkvnSBdI/Ef5QWXrsPyKU4PYBtnWWgyxRspH+FBA==", + "requires": {} }, "@angular/compiler": { "version": "9.1.4", "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.1.4.tgz", - "integrity": "sha512-B+f3lviFNEJtL9V9exSKYPSz2Ddb6dxgPzQR7GSjGikDo+fKMtC1PjNwgJooS9gavhQx30uwkEEMIPYQbM6nNA==" + "integrity": "sha512-B+f3lviFNEJtL9V9exSKYPSz2Ddb6dxgPzQR7GSjGikDo+fKMtC1PjNwgJooS9gavhQx30uwkEEMIPYQbM6nNA==", + "requires": {} }, "@angular/compiler-cli": { "version": "9.1.4", @@ -511,12 +18851,14 @@ "@angular/core": { "version": "9.1.4", "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.1.4.tgz", - "integrity": "sha512-ND240vncmVD2KVe/KSQU3d/DxxoRipFg1+jFOFZGt0n0orCBHk/V1fu9iaG1sRyldL0+rCQ+fTI+1N4DTmMnxA==" + "integrity": "sha512-ND240vncmVD2KVe/KSQU3d/DxxoRipFg1+jFOFZGt0n0orCBHk/V1fu9iaG1sRyldL0+rCQ+fTI+1N4DTmMnxA==", + "requires": {} }, "@angular/forms": { "version": "9.1.4", "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-9.1.4.tgz", - "integrity": "sha512-Njt+pMLfPBchL0/ayIjJqXL6ZfM4Ccvf7KO1wS1HMzh3QlmfNa0JSgc4pfrbRJAMN9g7V/FYLyKejs1bJZkenA==" + "integrity": "sha512-Njt+pMLfPBchL0/ayIjJqXL6ZfM4Ccvf7KO1wS1HMzh3QlmfNa0JSgc4pfrbRJAMN9g7V/FYLyKejs1bJZkenA==", + "requires": {} }, "@angular/language-service": { "version": "9.1.4", @@ -527,27 +18869,32 @@ "@angular/material": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/@angular/material/-/material-9.2.2.tgz", - "integrity": "sha512-gdQiMJ6PtW/5fd+0mglHFyzxULDCBGjn9RTET3sUq2rkc9+jBXr4OvnsUyBWSnqqv97XqotVDIx5JgE4/YX/Rw==" + "integrity": "sha512-gdQiMJ6PtW/5fd+0mglHFyzxULDCBGjn9RTET3sUq2rkc9+jBXr4OvnsUyBWSnqqv97XqotVDIx5JgE4/YX/Rw==", + "requires": {} }, "@angular/material-moment-adapter": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-9.2.2.tgz", - "integrity": "sha512-hijj2VVC7Oy9XGVYE+FsdI521w/9v453jP2VUH+CCRoeoCopdNS+dh1vacSAGf21UXwH9LJ5E6kI9RsmfwF/Ig==" + "integrity": "sha512-hijj2VVC7Oy9XGVYE+FsdI521w/9v453jP2VUH+CCRoeoCopdNS+dh1vacSAGf21UXwH9LJ5E6kI9RsmfwF/Ig==", + "requires": {} }, "@angular/platform-browser": { "version": "9.1.4", "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-9.1.4.tgz", - "integrity": "sha512-mBCHfTl+5tQfaUiGlDujP7mFBzovFc54Zi2kcCE8DSdSSVQ2TPBo6hXa6y2cL3hJPFZzQ7mC4ORFrsGADhHn/w==" + "integrity": "sha512-mBCHfTl+5tQfaUiGlDujP7mFBzovFc54Zi2kcCE8DSdSSVQ2TPBo6hXa6y2cL3hJPFZzQ7mC4ORFrsGADhHn/w==", + "requires": {} }, "@angular/platform-browser-dynamic": { "version": "9.1.4", "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.1.4.tgz", - "integrity": "sha512-YtVbnxyS6FU7xNpA6A95tmSfrB8+WC7OH3mbP8M9NaGk0OYz8B/JOe1HByP4JRpEGCvBtXdJ2NSW/MpLIT8SiQ==" + "integrity": "sha512-YtVbnxyS6FU7xNpA6A95tmSfrB8+WC7OH3mbP8M9NaGk0OYz8B/JOe1HByP4JRpEGCvBtXdJ2NSW/MpLIT8SiQ==", + "requires": {} }, "@angular/router": { "version": "9.1.4", "resolved": "https://registry.npmjs.org/@angular/router/-/router-9.1.4.tgz", - "integrity": "sha512-yUyjCgG2P2Jh8MvoyC6yirmAtx1Qe7MKLuLvsa9WOB571QNEcNLTYMfAMHUKsQTcE/+o984QyLlneoibgI9wFA==" + "integrity": "sha512-yUyjCgG2P2Jh8MvoyC6yirmAtx1Qe7MKLuLvsa9WOB571QNEcNLTYMfAMHUKsQTcE/+o984QyLlneoibgI9wFA==", + "requires": {} }, "@babel/code-frame": { "version": "7.8.3", @@ -1739,27 +20086,32 @@ "@fullcalendar/daygrid": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-4.4.0.tgz", - "integrity": "sha512-pDfvL0XZxKHTZ4VFOmwaYe3LmuABEIZsEopeqQ8y5O6BDen9KCbJqgHeCI8FpASSBd6bNlUx7il7EHdSoHhgIw==" + "integrity": "sha512-pDfvL0XZxKHTZ4VFOmwaYe3LmuABEIZsEopeqQ8y5O6BDen9KCbJqgHeCI8FpASSBd6bNlUx7il7EHdSoHhgIw==", + "requires": {} }, "@fullcalendar/interaction": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-4.4.0.tgz", - "integrity": "sha512-nGu0ZzYYlNpIhqfyv3JupteWKFETs3W1MzbRJcEZkuPncn4BooEi4A2blgHfacHAmmpaNkT84tAmhzi734MFBA==" + "integrity": "sha512-nGu0ZzYYlNpIhqfyv3JupteWKFETs3W1MzbRJcEZkuPncn4BooEi4A2blgHfacHAmmpaNkT84tAmhzi734MFBA==", + "requires": {} }, "@fullcalendar/list": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@fullcalendar/list/-/list-4.4.0.tgz", - "integrity": "sha512-uUDSPS71czNTK5Z3x3HzeE3KIvqkCfvhY+mGFdaAL6+7VpCwEIfB6s3GIJOjzu9TONmczMk4jdq0b1WUFLY5PQ==" + "integrity": "sha512-uUDSPS71czNTK5Z3x3HzeE3KIvqkCfvhY+mGFdaAL6+7VpCwEIfB6s3GIJOjzu9TONmczMk4jdq0b1WUFLY5PQ==", + "requires": {} }, "@fullcalendar/moment": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@fullcalendar/moment/-/moment-4.4.0.tgz", - "integrity": "sha512-sW2F7z0E1+kBvBduGiXVYJtIWj2AWeUQQoiLA+xgprsyljzigwnI+9J2iviaB9uL7LIbCSnPrOZmhpVTufmPvQ==" + "integrity": "sha512-sW2F7z0E1+kBvBduGiXVYJtIWj2AWeUQQoiLA+xgprsyljzigwnI+9J2iviaB9uL7LIbCSnPrOZmhpVTufmPvQ==", + "requires": {} }, "@fullcalendar/rrule": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@fullcalendar/rrule/-/rrule-4.4.0.tgz", - "integrity": "sha512-pXe3kSShg9CQ5gr0J0IGMYAwVlBv6j9yotRfJUrCY7xUWNkqTLAmburW7Q7KNlDMOLuiFbM/twBYZYiIjjTWpg==" + "integrity": "sha512-pXe3kSShg9CQ5gr0J0IGMYAwVlBv6j9yotRfJUrCY7xUWNkqTLAmburW7Q7KNlDMOLuiFbM/twBYZYiIjjTWpg==", + "requires": {} }, "@fullcalendar/timegrid": { "version": "4.4.0", @@ -2196,16 +20548,6 @@ "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", "dev": true }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -2303,13 +20645,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", - "dev": true + "dev": true, + "requires": {} }, "ajv-keywords": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", - "dev": true + "dev": true, + "requires": {} }, "alphanum-sort": { "version": "1.0.2", @@ -3272,7 +21616,8 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.0.tgz", "integrity": "sha512-7p4Kn/gffhQaavNfyDFg7LS5S/UT1JAjyGd4UqR2+jzoYF02eDkj0Ec3+48TsIa4zghjLY87nQHIh/ecK9qLdw==", - "dev": true + "dev": true, + "requires": {} }, "class-utils": { "version": "0.3.6", @@ -6974,6 +25319,16 @@ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", "dev": true }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -7254,7 +25609,8 @@ "version": "1.5.3", "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.5.3.tgz", "integrity": "sha512-ci0VrjuCaFj+9d1tYlTE3KIPUCp0rz874zWWU3JgCMqGIyw5ke+BXWFPOAGAqUdCJcrMwneyvp1zFXA74MiPUA==", - "dev": true + "dev": true, + "requires": {} }, "karma-source-map-support": { "version": "1.4.0", @@ -8151,7 +26507,8 @@ "ngx-quill": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/ngx-quill/-/ngx-quill-9.1.0.tgz", - "integrity": "sha512-3VkacaTNGP3akHpjmxT+mvhfM/YeDsuQCwZWI1kKvB66BKSIaiZJOM8E9MHV++QOHSQ0nJzU6TUgYgxaAaSj0g==" + "integrity": "sha512-3VkacaTNGP3akHpjmxT+mvhfM/YeDsuQCwZWI1kKvB66BKSIaiZJOM8E9MHV++QOHSQ0nJzU6TUgYgxaAaSj0g==", + "requires": {} }, "nice-try": { "version": "1.0.5", @@ -8367,9 +26724,9 @@ "integrity": "sha512-6jb34hX/iYNQebqWUHtU8YF6Cjb1H6ouTFPClYsyiW6lpFkljTpdeftm53rRojtja1rKAvKNIIiTS5Sjpw4wsA==", "dev": true, "requires": { - "JSONStream": "^1.3.4", "bluebird": "^3.5.1", "figgy-pudding": "^3.4.1", + "JSONStream": "^1.3.4", "lru-cache": "^5.1.1", "make-fetch-happen": "^5.0.0", "npm-package-arg": "^6.1.0", @@ -11894,6 +30251,15 @@ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", "dev": true }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -11959,15 +30325,6 @@ "es-abstract": "^1.17.5" } }, - "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" - } - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -13573,24 +31930,24 @@ "dev": true, "optional": true }, - "string-width": { - "version": "1.0.2", + "string_decoder": { + "version": "1.1.1", "bundled": true, "dev": true, "optional": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "safe-buffer": "~5.1.0" } }, - "string_decoder": { - "version": "1.1.1", + "string-width": { + "version": "1.0.2", "bundled": true, "dev": true, "optional": true, "requires": { - "safe-buffer": "~5.1.0" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "strip-ansi": { @@ -14520,24 +32877,24 @@ "dev": true, "optional": true }, - "string-width": { - "version": "1.0.2", + "string_decoder": { + "version": "1.1.1", "bundled": true, "dev": true, "optional": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "safe-buffer": "~5.1.0" } }, - "string_decoder": { - "version": "1.1.1", + "string-width": { + "version": "1.0.2", "bundled": true, "dev": true, "optional": true, "requires": { - "safe-buffer": "~5.1.0" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "strip-ansi": { diff --git a/webapp/frontend/src/app/data/mock/device/details/sdc.ts b/webapp/frontend/src/app/data/mock/device/details/sdc.ts index 4bf402f..692437f 100644 --- a/webapp/frontend/src/app/data/mock/device/details/sdc.ts +++ b/webapp/frontend/src/app/data/mock/device/details/sdc.ts @@ -23,6 +23,203 @@ export const sdc = { "device_status": 1 }, "smart_results": [{ + "date": "2020-07-08T13:48:23Z", + "device_wwn": "0x5000cca264ec3183", + "device_protocol": "ATA", + "temp": 25, + "power_on_hours": 65592, + "power_cycle_count": 86, + "attrs": { + "1": { + "attribute_id": 1, + "name": "Read Error Rate", + "value": 100, + "thresh": 16, + "worst": 100, + "raw_value": 0, + "raw_string": "0", + "when_failed": "", + "transformed_value": 0 + }, + "10": { + "attribute_id": 10, + "name": "Spin Retry Count", + "value": 100, + "thresh": 60, + "worst": 100, + "raw_value": 0, + "raw_string": "0", + "when_failed": "", + "transformed_value": 0, + "status": "passed" + }, + "12": { + "attribute_id": 12, + "name": "Power Cycle Count", + "value": 100, + "thresh": 0, + "worst": 100, + "raw_value": 86, + "raw_string": "86", + "when_failed": "", + "transformed_value": 0 + }, + "192": { + "attribute_id": 192, + "name": "Power-off Retract Count", + "value": 95, + "thresh": 0, + "worst": 95, + "raw_value": 6244, + "raw_string": "6244", + "when_failed": "", + "transformed_value": 0 + }, + "193": { + "attribute_id": 193, + "name": "Load Cycle Count", + "value": 95, + "thresh": 0, + "worst": 95, + "raw_value": 6244, + "raw_string": "6244", + "when_failed": "", + "transformed_value": 0 + }, + "194": { + "attribute_id": 194, + "name": "Temperature", + "value": 240, + "thresh": 0, + "worst": 240, + "raw_value": 167504969753, + "raw_string": "25 (Min/Max 19/39)", + "when_failed": "", + "transformed_value": 0 + }, + "196": { + "attribute_id": 196, + "name": "Reallocation Event Count", + "value": 1, + "thresh": 0, + "worst": 1, + "raw_value": 3831, + "raw_string": "3831", + "when_failed": "", + "transformed_value": 0 + }, + "197": { + "attribute_id": 197, + "name": "Current Pending Sector Count", + "value": 100, + "thresh": 0, + "worst": 100, + "raw_value": 8, + "raw_string": "8", + "when_failed": "", + "transformed_value": 0 + }, + "198": { + "attribute_id": 198, + "name": "(Offline) Uncorrectable Sector Count", + "value": 100, + "thresh": 0, + "worst": 100, + "raw_value": 0, + "raw_string": "0", + "when_failed": "", + "transformed_value": 0 + }, + "199": { + "attribute_id": 199, + "name": "UltraDMA CRC Error Count", + "value": 200, + "thresh": 0, + "worst": 200, + "raw_value": 0, + "raw_string": "0", + "when_failed": "", + "transformed_value": 0 + }, + "2": { + "attribute_id": 2, + "name": "Throughput Performance", + "value": 136, + "thresh": 54, + "worst": 136, + "raw_value": 91, + "raw_string": "91", + "when_failed": "", + "transformed_value": 0 + }, + "3": { + "attribute_id": 3, + "name": "Spin-Up Time", + "value": 125, + "thresh": 24, + "worst": 125, + "raw_value": 17192124596, + "raw_string": "180 (Average 187)", + "when_failed": "", + "transformed_value": 0 + }, + "4": { + "attribute_id": 4, + "name": "Start/Stop Count", + "value": 100, + "thresh": 0, + "worst": 100, + "raw_value": 86, + "raw_string": "86", + "when_failed": "", + "transformed_value": 0 + }, + "5": { + "attribute_id": 5, + "name": "Reallocated Sectors Count", + "value": 1, + "thresh": 5, + "worst": 1, + "raw_value": 1975, + "raw_string": "1975", + "when_failed": "now", + "transformed_value": 0 + }, + "7": { + "attribute_id": 7, + "name": "Seek Error Rate", + "value": 100, + "thresh": 67, + "worst": 100, + "raw_value": 0, + "raw_string": "0", + "when_failed": "", + "transformed_value": 0 + }, + "8": { + "attribute_id": 8, + "name": "Seek Time Performance", + "value": 118, + "thresh": 20, + "worst": 118, + "raw_value": 33, + "raw_string": "33", + "when_failed": "", + "transformed_value": 0 + }, + "9": { + "attribute_id": 9, + "name": "Power-On Hours", + "value": 91, + "thresh": 0, + "worst": 91, + "raw_value": 65592, + "raw_string": "65592", + "when_failed": "", + "transformed_value": 0 + } + } + }, { "date": "2020-07-08T13:48:23Z", "device_wwn": "0x5000cca264ec3183", "device_protocol": "ATA", diff --git a/webapp/frontend/src/app/data/mock/device/details/sdd.ts b/webapp/frontend/src/app/data/mock/device/details/sdd.ts index 35e73d1..ccf09b0 100644 --- a/webapp/frontend/src/app/data/mock/device/details/sdd.ts +++ b/webapp/frontend/src/app/data/mock/device/details/sdd.ts @@ -122,6 +122,106 @@ export const sdd = { "transformed_value": 0 } } + },{ + "date": "2020-08-21T22:27:02Z", + "device_wwn": "0x5000cca252c859cc", + "device_protocol": "SCSI", + "temp": 34, + "power_on_hours": 43549, + "power_cycle_count": 0, + "attrs": { + "read_correction_algorithm_invocations": { + "attribute_id": "read_correction_algorithm_invocations", + "name": "Read Correction Algorithm Invocations", + "value": 0, + "thresh": -1, + "transformed_value": 0 + }, + "read_errors_corrected_by_eccdelayed": { + "attribute_id": "read_errors_corrected_by_eccdelayed", + "name": "Read Errors Corrected by ECC Delayed", + "value": 0, + "thresh": -1, + "transformed_value": 0 + }, + "read_errors_corrected_by_eccfast": { + "attribute_id": "read_errors_corrected_by_eccfast", + "name": "Read Errors Corrected by ECC Fast", + "value": 300357663, + "thresh": -1, + "transformed_value": 0 + }, + "read_errors_corrected_by_rereads_rewrites": { + "attribute_id": "read_errors_corrected_by_rereads_rewrites", + "name": "Read Errors Corrected by ReReads/ReWrites", + "value": 0, + "thresh": 0, + "transformed_value": 0 + }, + "read_total_errors_corrected": { + "attribute_id": "read_total_errors_corrected", + "name": "Read Total Errors Corrected", + "value": 300357663, + "thresh": -1, + "transformed_value": 0 + }, + "read_total_uncorrected_errors": { + "attribute_id": "read_total_uncorrected_errors", + "name": "Read Total Uncorrected Errors", + "value": 0, + "thresh": 0, + "transformed_value": 0 + }, + "scsi_grown_defect_list": { + "attribute_id": "scsi_grown_defect_list", + "name": "Grown Defect List", + "value": 56, + "thresh": 0, + "transformed_value": 0 + }, + "write_correction_algorithm_invocations": { + "attribute_id": "write_correction_algorithm_invocations", + "name": "Write Correction Algorithm Invocations", + "value": 0, + "thresh": -1, + "transformed_value": 0 + }, + "write_errors_corrected_by_eccdelayed": { + "attribute_id": "write_errors_corrected_by_eccdelayed", + "name": "Write Errors Corrected by ECC Delayed", + "value": 0, + "thresh": -1, + "transformed_value": 0 + }, + "write_errors_corrected_by_eccfast": { + "attribute_id": "write_errors_corrected_by_eccfast", + "name": "Write Errors Corrected by ECC Fast", + "value": 0, + "thresh": -1, + "transformed_value": 0 + }, + "write_errors_corrected_by_rereads_rewrites": { + "attribute_id": "write_errors_corrected_by_rereads_rewrites", + "name": "Write Errors Corrected by ReReads/ReWrites", + "value": 0, + "thresh": 0, + "transformed_value": 0 + }, + "write_total_errors_corrected": { + "attribute_id": "write_total_errors_corrected", + "name": "Write Total Errors Corrected", + "value": 0, + "thresh": -1, + "transformed_value": 0 + }, + "write_total_uncorrected_errors": { + "attribute_id": "write_total_uncorrected_errors", + "name": "Write Total Uncorrected Errors", + "value": 0, + "thresh": 0, + "transformed_value": 0 + } + } }] }, "metadata": { diff --git a/webapp/frontend/src/app/data/mock/device/details/sde.ts b/webapp/frontend/src/app/data/mock/device/details/sde.ts index 3a05f9a..4e08e00 100644 --- a/webapp/frontend/src/app/data/mock/device/details/sde.ts +++ b/webapp/frontend/src/app/data/mock/device/details/sde.ts @@ -1,22 +1,24 @@ export const sde = { "data": { - "CreatedAt": "2020-08-28T07:55:27.768220079Z", - "UpdatedAt": "2020-09-08T21:39:26.578973-07:00", - "DeletedAt": null, - "wwn": "0x5000cca264ebc248", - "device_name": "sde", - "manufacturer": "SEAGATE", - "model_name": "WDC_WD140EDFZ-11A0VA0", - "interface_type": "SCSI", - "interface_speed": "", - "serial_number": "9RK3XXXXX", - "firmware": "", - "rotational_speed": 10500, - "capacity": 1200243695616, - "form_factor": "2.5 inches", - "smart_support": false, - "device_protocol": "SCSI", - "device_type": "scsi", + "device": { + "CreatedAt": "2020-08-28T07:55:27.768220079Z", + "UpdatedAt": "2020-09-08T21:39:26.578973-07:00", + "DeletedAt": null, + "wwn": "0x5000cca264ebc248", + "device_name": "sde", + "manufacturer": "SEAGATE", + "model_name": "WDC_WD140EDFZ-11A0VA0", + "interface_type": "SCSI", + "interface_speed": "", + "serial_number": "9RK3XXXXX", + "firmware": "", + "rotational_speed": 10500, + "capacity": 1200243695616, + "form_factor": "2.5 inches", + "smart_support": false, + "device_protocol": "SCSI", + "device_type": "scsi", + }, "smart_results": [{ "ID": 48, "CreatedAt": "2020-09-08T21:39:26.579623-07:00", diff --git a/webapp/frontend/src/app/data/mock/device/details/sdf.ts b/webapp/frontend/src/app/data/mock/device/details/sdf.ts index cdf96da..c624dab 100644 --- a/webapp/frontend/src/app/data/mock/device/details/sdf.ts +++ b/webapp/frontend/src/app/data/mock/device/details/sdf.ts @@ -1,22 +1,25 @@ export const sdf = { "data": { - "CreatedAt": "2020-09-29T03:17:30.813487336Z", - "UpdatedAt": "2020-09-29T03:17:31.04293448Z", - "DeletedAt": null, - "wwn": "0x5000c500c0558f02", - "device_name": "sdc", - "manufacturer": "", - "model_name": "ST8000VN004-2M2101", - "interface_type": "", - "interface_speed": "6.0 Gb/s", - "serial_number": "WKD01Y5S", - "firmware": "SC60", - "rotational_speed": 7200, - "capacity": 8001563222016, - "form_factor": "3.5 inches", - "smart_support": false, - "device_protocol": "ATA", - "device_type": "scsi", + "device": { + "CreatedAt": "2020-09-29T03:17:30.813487336Z", + "UpdatedAt": "2020-09-29T03:17:31.04293448Z", + "DeletedAt": null, + "wwn": "0x5000c500c0558f02", + "device_name": "sdc", + "manufacturer": "", + "model_name": "ST8000VN004-2M2101", + "interface_type": "", + "interface_speed": "6.0 Gb/s", + "serial_number": "WKD01Y5S", + "firmware": "SC60", + "rotational_speed": 7200, + "capacity": 8001563222016, + "form_factor": "3.5 inches", + "smart_support": false, + "device_protocol": "ATA", + "device_type": "scsi", + "device_status": 2, + }, "smart_results": [{ "ID": 1, "CreatedAt": "2020-09-29T03:17:31.063859162Z", @@ -394,6 +397,383 @@ export const sdf = { }], "nvme_attributes": [], "scsi_attributes": [] + }, { + "ID": 1, + "CreatedAt": "2020-09-29T03:17:31.063859162Z", + "UpdatedAt": "2020-09-29T03:17:31.063859162Z", + "DeletedAt": null, + "device_wwn": "0x5000c500c0558f02", + "date": "2020-09-29T03:17:30Z", + "smart_status": "passed", + "temp": 39, + "power_on_hours": 9499, + "power_cycle_count": 22, + "ata_attributes": [{ + "ID": 1, + "CreatedAt": "2020-09-29T03:17:31.064174997Z", + "UpdatedAt": "2020-09-29T03:17:31.064174997Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 1, + "name": "Read Error Rate", + "value": 79, + "worst": 64, + "thresh": 44, + "raw_value": 78022392, + "raw_string": "78022392", + "when_failed": "", + "transformed_value": 0, + "status": "passed" + }, { + "ID": 2, + "CreatedAt": "2020-09-29T03:17:31.064379412Z", + "UpdatedAt": "2020-09-29T03:17:31.064379412Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 3, + "name": "Spin-Up Time", + "value": 95, + "worst": 86, + "thresh": 0, + "raw_value": 0, + "raw_string": "0", + "when_failed": "", + "transformed_value": 0, + "status": "warn", + "status_reason": "Observed Failure Rate for Attribute is greater than 10%", + "failure_rate": 0.11452195377351217 + }, { + "ID": 3, + "CreatedAt": "2020-09-29T03:17:31.064506775Z", + "UpdatedAt": "2020-09-29T03:17:31.064506775Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 4, + "name": "Start/Stop Count", + "value": 100, + "worst": 100, + "thresh": 20, + "raw_value": 220, + "raw_string": "220", + "when_failed": "", + "transformed_value": 0, + "status": "passed" + }, { + "ID": 4, + "CreatedAt": "2020-09-29T03:17:31.064621265Z", + "UpdatedAt": "2020-09-29T03:17:31.064621265Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 5, + "name": "Reallocated Sectors Count", + "value": 100, + "worst": 100, + "thresh": 10, + "raw_value": 0, + "raw_string": "0", + "when_failed": "", + "transformed_value": 0, + "status": "passed", + "failure_rate": 0.025169175350572493 + }, { + "ID": 5, + "CreatedAt": "2020-09-29T03:17:31.064742769Z", + "UpdatedAt": "2020-09-29T03:17:31.064742769Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 7, + "name": "Seek Error Rate", + "value": 86, + "worst": 60, + "thresh": 45, + "raw_value": 4679507461, + "raw_string": "4679507461", + "when_failed": "", + "transformed_value": 0, + "status": "passed", + "failure_rate": 0.08725919610118257 + }, { + "ID": 6, + "CreatedAt": "2020-09-29T03:17:31.064850152Z", + "UpdatedAt": "2020-09-29T03:17:31.064850152Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 9, + "name": "Power-On Hours", + "value": 90, + "worst": 90, + "thresh": 0, + "raw_value": 9499, + "raw_string": "9499", + "when_failed": "", + "transformed_value": 0, + "status": "passed" + }, { + "ID": 7, + "CreatedAt": "2020-09-29T03:17:31.064970318Z", + "UpdatedAt": "2020-09-29T03:17:31.064970318Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 10, + "name": "Spin Retry Count", + "value": 100, + "worst": 100, + "thresh": 97, + "raw_value": 0, + "raw_string": "0", + "when_failed": "", + "transformed_value": 0, + "status": "passed", + "failure_rate": 0.05459827163896099 + }, { + "ID": 8, + "CreatedAt": "2020-09-29T03:17:31.065072898Z", + "UpdatedAt": "2020-09-29T03:17:31.065072898Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 12, + "name": "Power Cycle Count", + "value": 100, + "worst": 100, + "thresh": 20, + "raw_value": 22, + "raw_string": "22", + "when_failed": "", + "transformed_value": 0, + "status": "passed", + "failure_rate": 0.038210930067894826 + }, { + "ID": 9, + "CreatedAt": "2020-09-29T03:17:31.065366547Z", + "UpdatedAt": "2020-09-29T03:17:31.065366547Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 18, + "name": "Unknown_Attribute", + "value": 100, + "worst": 100, + "thresh": 50, + "raw_value": 0, + "raw_string": "0", + "when_failed": "", + "transformed_value": 0, + "status": "passed" + }, { + "ID": 10, + "CreatedAt": "2020-09-29T03:17:31.065539403Z", + "UpdatedAt": "2020-09-29T03:17:31.065539403Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 187, + "name": "Reported Uncorrectable Errors", + "value": 100, + "worst": 100, + "thresh": 0, + "raw_value": 0, + "raw_string": "0", + "when_failed": "", + "transformed_value": 0, + "status": "passed", + "failure_rate": 0.028130798308190524 + }, { + "ID": 11, + "CreatedAt": "2020-09-29T03:17:31.065665808Z", + "UpdatedAt": "2020-09-29T03:17:31.065665808Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 188, + "name": "Command Timeout", + "value": 100, + "worst": 100, + "thresh": 0, + "raw_value": 0, + "raw_string": "0", + "when_failed": "", + "transformed_value": 0, + "status": "passed", + "failure_rate": 0.024893587674442153 + }, { + "ID": 12, + "CreatedAt": "2020-09-29T03:17:31.065780779Z", + "UpdatedAt": "2020-09-29T03:17:31.065780779Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 190, + "name": "Temperature Difference", + "value": 61, + "worst": 46, + "thresh": 40, + "raw_value": 740294695, + "raw_string": "39 (Min/Max 32/44)", + "when_failed": "", + "transformed_value": 0, + "status": "passed" + }, { + "ID": 13, + "CreatedAt": "2020-09-29T03:17:31.065931499Z", + "UpdatedAt": "2020-09-29T03:17:31.065931499Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 192, + "name": "Power-off Retract Count", + "value": 100, + "worst": 100, + "thresh": 0, + "raw_value": 4, + "raw_string": "4", + "when_failed": "", + "transformed_value": 0, + "status": "passed", + "failure_rate": 0.0738571777154862 + }, { + "ID": 14, + "CreatedAt": "2020-09-29T03:17:31.066043189Z", + "UpdatedAt": "2020-09-29T03:17:31.066043189Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 193, + "name": "Load Cycle Count", + "value": 100, + "worst": 100, + "thresh": 0, + "raw_value": 1680, + "raw_string": "1680", + "when_failed": "", + "transformed_value": 0, + "status": "passed" + }, { + "ID": 15, + "CreatedAt": "2020-09-29T03:17:31.066162028Z", + "UpdatedAt": "2020-09-29T03:17:31.066162028Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 194, + "name": "Temperature", + "value": 39, + "worst": 54, + "thresh": 0, + "raw_value": 81604378663, + "raw_string": "39 (0 19 0 0 0)", + "when_failed": "", + "transformed_value": 39, + "status": "passed" + }, { + "ID": 16, + "CreatedAt": "2020-09-29T03:17:31.066270283Z", + "UpdatedAt": "2020-09-29T03:17:31.066270283Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 195, + "name": "Hardware ECC Recovered", + "value": 79, + "worst": 64, + "thresh": 0, + "raw_value": 78022392, + "raw_string": "78022392", + "when_failed": "", + "transformed_value": 0, + "status": "passed" + }, { + "ID": 17, + "CreatedAt": "2020-09-29T03:17:31.066381938Z", + "UpdatedAt": "2020-09-29T03:17:31.066381938Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 197, + "name": "Current Pending Sector Count", + "value": 100, + "worst": 100, + "thresh": 0, + "raw_value": 0, + "raw_string": "0", + "when_failed": "", + "transformed_value": 0, + "status": "passed", + "failure_rate": 0.025540791394761345 + }, { + "ID": 18, + "CreatedAt": "2020-09-29T03:17:31.066497143Z", + "UpdatedAt": "2020-09-29T03:17:31.066497143Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 198, + "name": "(Offline) Uncorrectable Sector Count", + "value": 100, + "worst": 100, + "thresh": 0, + "raw_value": 0, + "raw_string": "0", + "when_failed": "", + "transformed_value": 0, + "status": "passed", + "failure_rate": 0.028675322159886437 + }, { + "ID": 19, + "CreatedAt": "2020-09-29T03:17:31.066632808Z", + "UpdatedAt": "2020-09-29T03:17:31.066632808Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 199, + "name": "UltraDMA CRC Error Count", + "value": 200, + "worst": 200, + "thresh": 0, + "raw_value": 0, + "raw_string": "0", + "when_failed": "", + "transformed_value": 0, + "status": "passed" + }, { + "ID": 20, + "CreatedAt": "2020-09-29T03:17:31.066757646Z", + "UpdatedAt": "2020-09-29T03:17:31.066757646Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 240, + "name": "Head Flying Hours", + "value": 100, + "worst": 253, + "thresh": 0, + "raw_value": 21887153349770, + "raw_string": "9354 (19 232 0)", + "when_failed": "", + "transformed_value": 0, + "status": "passed" + }, { + "ID": 21, + "CreatedAt": "2020-09-29T03:17:31.06687199Z", + "UpdatedAt": "2020-09-29T03:17:31.06687199Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 241, + "name": "Total LBAs Written", + "value": 100, + "worst": 253, + "thresh": 0, + "raw_value": 78115437520, + "raw_string": "78115437520", + "when_failed": "", + "transformed_value": 0, + "status": "passed" + }, { + "ID": 22, + "CreatedAt": "2020-09-29T03:17:31.066984948Z", + "UpdatedAt": "2020-09-29T03:17:31.066984948Z", + "DeletedAt": null, + "smart_id": 1, + "attribute_id": 242, + "name": "Total LBAs Read", + "value": 100, + "worst": 253, + "thresh": 0, + "raw_value": 226428055205, + "raw_string": "226428055205", + "when_failed": "", + "transformed_value": 0, + "status": "passed" + }], + "nvme_attributes": [], + "scsi_attributes": [] }] }, "metadata": { "1": { From fa5d0e44c4891527872e539c64bc8d5fd2782052 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Mon, 2 Aug 2021 21:52:45 -0700 Subject: [PATCH 013/114] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b218b2c..9650190 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,6 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/AnalogJ/scrutiny?style=flat-square)](https://goreportcard.com/report/github.com/AnalogJ/scrutiny) [![GitHub release](http://img.shields.io/github/release/AnalogJ/scrutiny.svg?style=flat-square)](https://github.com/AnalogJ/scrutiny/releases) - WebUI for smartd S.M.A.R.T monitoring > NOTE: Scrutiny is a Work-in-Progress and still has some rough edges. @@ -23,6 +22,8 @@ WebUI for smartd S.M.A.R.T monitoring # Introduction +> WARNING: Once the [InfluxDB](https://github.com/AnalogJ/scrutiny/tree/influxdb) branch is merged, Scrutiny will use both sqlite and InfluxDB for data storage. Unfortunately, this may not be backwards compatible with the database structures in the master (sqlite only) branch. + If you run a server with more than a couple of hard drives, you're probably already familiar with S.M.A.R.T and the `smartd` daemon. If not, it's an incredible open source project described as the following: > smartd is a daemon that monitors the Self-Monitoring, Analysis and Reporting Technology (SMART) system built into many ATA, IDE and SCSI-3 hard drives. The purpose of SMART is to monitor the reliability of the hard drive and predict drive failures, and to carry out different types of drive self-tests. From 6d4196085ea6943865afda378f259ede00fca2de Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Mon, 2 Aug 2021 21:53:44 -0700 Subject: [PATCH 014/114] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9650190..ec090c5 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,13 @@ WebUI for smartd S.M.A.R.T monitoring > NOTE: Scrutiny is a Work-in-Progress and still has some rough edges. +> +> WARNING: Once the [InfluxDB](https://github.com/AnalogJ/scrutiny/tree/influxdb) branch is merged, Scrutiny will use both sqlite and InfluxDB for data storage. Unfortunately, this may not be backwards compatible with the database structures in the master (sqlite only) branch. [![](docs/dashboard.png)](https://imgur.com/a/5k8qMzS) # Introduction -> WARNING: Once the [InfluxDB](https://github.com/AnalogJ/scrutiny/tree/influxdb) branch is merged, Scrutiny will use both sqlite and InfluxDB for data storage. Unfortunately, this may not be backwards compatible with the database structures in the master (sqlite only) branch. - If you run a server with more than a couple of hard drives, you're probably already familiar with S.M.A.R.T and the `smartd` daemon. If not, it's an incredible open source project described as the following: > smartd is a daemon that monitors the Self-Monitoring, Analysis and Reporting Technology (SMART) system built into many ATA, IDE and SCSI-3 hard drives. The purpose of SMART is to monitor the reliability of the hard drive and predict drive failures, and to carry out different types of drive self-tests. From abe7a1650714d05f8d3502f12da419f3a3a8c06a Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 Aug 2021 23:26:40 -0700 Subject: [PATCH 015/114] creating influxdb config file during startup. --- rootfs/etc/services.d/influxdb/run | 13 +++++++++++++ rootfs/scrutiny/.gitinclude | 0 rootfs/scrutiny/influxdb/config.yaml | 4 ---- 3 files changed, 13 insertions(+), 4 deletions(-) delete mode 100644 rootfs/scrutiny/.gitinclude delete mode 100644 rootfs/scrutiny/influxdb/config.yaml diff --git a/rootfs/etc/services.d/influxdb/run b/rootfs/etc/services.d/influxdb/run index e862aaa..d30ad11 100644 --- a/rootfs/etc/services.d/influxdb/run +++ b/rootfs/etc/services.d/influxdb/run @@ -1,4 +1,17 @@ #!/usr/bin/with-contenv bash +mkdir -p /scrutiny/influxdb/ + +if [ -f "/scrutiny/influxdb/config.yaml" ]; then + echo "influxdb config file already exists. skipping." +else +cat << 'EOF' > /scrutiny/influxdb/config.yaml +bolt-path: /scrutiny/influxdb/influxd.bolt +engine-path: /scrutiny/influxdb/engine +http-bind-address: ":8086" +reporting-disabled: true +EOF +fi + echo "starting influxdb" influxd run diff --git a/rootfs/scrutiny/.gitinclude b/rootfs/scrutiny/.gitinclude deleted file mode 100644 index e69de29..0000000 diff --git a/rootfs/scrutiny/influxdb/config.yaml b/rootfs/scrutiny/influxdb/config.yaml deleted file mode 100644 index 245d541..0000000 --- a/rootfs/scrutiny/influxdb/config.yaml +++ /dev/null @@ -1,4 +0,0 @@ -bolt-path: /scrutiny/influxdb/influxd.bolt -engine-path: /scrutiny/influxdb/engine -http-bind-address: ":8086" -reporting-disabled: true From 975c034925ec909ca5152470c09242a398672331 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 23 Oct 2021 10:35:32 -0700 Subject: [PATCH 016/114] WIP downsample scripts. --- .../pkg/database/scrutiny_repository.go | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index 58fc514..885afb9 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -91,7 +91,10 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field // Get query client queryAPI := client.QueryAPI(appConfig.GetString("web.influxdb.org")) - if writeAPI == nil || queryAPI == nil { + // Get task client + taskAPI := client.TasksAPI() + + if writeAPI == nil || queryAPI == nil || taskAPI == nil { return nil, fmt.Errorf("Failed to connect to influxdb!") } @@ -101,6 +104,7 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field influxClient: client, influxWriteApi: writeAPI, influxQueryApi: queryAPI, + influxTaskApi: taskAPI, gormClient: database, } @@ -113,6 +117,7 @@ type scrutinyRepository struct { influxWriteApi api.WriteAPIBlocking influxQueryApi api.QueryAPI + influxTaskApi api.TasksAPI influxClient influxdb2.Client gormClient *gorm.DB @@ -123,6 +128,26 @@ func (sr *scrutinyRepository) Close() error { return nil } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Tasks +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +func (sr *scrutinyRepository) InitTasks(ctx context.Context) error { + flux := "" + + //weekly on Sunday at 1:00am + sr.influxTaskApi.CreateTaskWithCron(ctx, "tsk-weekly-aggr", flux, "0 1 * * 0", sr.appConfig.GetString("web.influxdb.org")) + + //monthly on first day of the month at 1:30am + sr.influxTaskApi.CreateTaskWithCron(ctx, "tsk-monthly-aggr", flux, "30 1 1 * *", sr.appConfig.GetString("web.influxdb.org")) + + //yearly on the frist day of the year at 2:00am + sr.influxTaskApi.CreateTaskWithCron(ctx, "tsk-yearly-aggr", flux, "0 2 1 1 *", sr.appConfig.GetString("web.influxdb.org")) +} + +func (sr *scrutinyRepository) DownsampleScript(aggregate string) (string, error){ + +} + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Device //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// From abfaa5259ebd7421b80d8fc1c0f06f79e01b9acf Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 23 Oct 2021 10:47:56 -0700 Subject: [PATCH 017/114] adding windows collector. --- .github/workflows/release-windows.yaml | 57 ++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 .github/workflows/release-windows.yaml diff --git a/.github/workflows/release-windows.yaml b/.github/workflows/release-windows.yaml new file mode 100644 index 0000000..5a93c3f --- /dev/null +++ b/.github/workflows/release-windows.yaml @@ -0,0 +1,57 @@ +# compiles Windows artifacts and attaches them to build +name: Release Windows + +on: + release: + # Only use the types keyword to narrow down the activity types that will trigger your workflow. + types: [published] + + # for testing, we can also trigger manually. remove this afterwards. + workflow_dispatch: + inputs: + version_bump_type: + description: 'noop' + required: false + default: 'patch' + +jobs: + + release-windows: + name: Release Windows + runs-on: windows-latest + env: + PROJECT_PATH: /go/src/github.com/analogj/scrutiny + GOPATH: /go + GOOS: windows + GOARCH: amd64 + steps: + - name: Checkout + uses: actions/checkout@v2 +# TODO: uncomment this +# with: +# ref: ${{github.event.release.tag_name}} + - uses: actions/setup-go@v2 + with: + go-version: '^1.13.1' # The Go version to download (if necessary) and use. + - name: Build Binaries + run: | + + mkdir -p $(dirname "$PROJECT_PATH") + cp -R $GITHUB_WORKSPACE $PROJECT_PATH + cd $PROJECT_PATH + + mkdir -p $GITHUB_WORKSPACE/dist + + echo "building collector binary (OS = ${GOOS}, ARCH = ${GOARCH})" + go build -ldflags "-extldflags=-static -X main.goos=${GOOS} -X main.goarch=${GOARCH}" -o $GITHUB_WORKSPACE/dist/scrutiny-collector-metrics-${GOOS}-${GOARCH}.exe -tags "static netgo" collector/cmd/collector-metrics/collector-metrics.go + + - name: Release Asset - Collector - windows-amd64 + id: upload-release-asset2 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: './dist/scrutiny-collector-metrics-windows-amd64' + asset_name: scrutiny-collector-metrics-windows-amd64 + asset_content_type: application/octet-stream From a4d151e3f7174b1f08dde1ef599fcfe1084f179d Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 23 Oct 2021 10:54:25 -0700 Subject: [PATCH 018/114] fixes for windows collector build. --- .github/workflows/release-windows.yaml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/release-windows.yaml b/.github/workflows/release-windows.yaml index 5a93c3f..3efe918 100644 --- a/.github/workflows/release-windows.yaml +++ b/.github/workflows/release-windows.yaml @@ -20,8 +20,6 @@ jobs: name: Release Windows runs-on: windows-latest env: - PROJECT_PATH: /go/src/github.com/analogj/scrutiny - GOPATH: /go GOOS: windows GOARCH: amd64 steps: @@ -35,11 +33,6 @@ jobs: go-version: '^1.13.1' # The Go version to download (if necessary) and use. - name: Build Binaries run: | - - mkdir -p $(dirname "$PROJECT_PATH") - cp -R $GITHUB_WORKSPACE $PROJECT_PATH - cd $PROJECT_PATH - mkdir -p $GITHUB_WORKSPACE/dist echo "building collector binary (OS = ${GOOS}, ARCH = ${GOARCH})" From fb564afe3003444382374a8e81e346ae6e322758 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 23 Oct 2021 10:57:02 -0700 Subject: [PATCH 019/114] fixes for windows collector build. --- .github/workflows/release-windows.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release-windows.yaml b/.github/workflows/release-windows.yaml index 3efe918..cedfc88 100644 --- a/.github/workflows/release-windows.yaml +++ b/.github/workflows/release-windows.yaml @@ -32,6 +32,7 @@ jobs: with: go-version: '^1.13.1' # The Go version to download (if necessary) and use. - name: Build Binaries + shell: bash run: | mkdir -p $GITHUB_WORKSPACE/dist From 5c492986a55334bcb1b7b573268566289b45fe43 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 23 Oct 2021 10:58:56 -0700 Subject: [PATCH 020/114] fixes for windows collector build. --- .github/workflows/release-windows.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-windows.yaml b/.github/workflows/release-windows.yaml index cedfc88..1e01482 100644 --- a/.github/workflows/release-windows.yaml +++ b/.github/workflows/release-windows.yaml @@ -38,7 +38,8 @@ jobs: echo "building collector binary (OS = ${GOOS}, ARCH = ${GOARCH})" go build -ldflags "-extldflags=-static -X main.goos=${GOOS} -X main.goarch=${GOARCH}" -o $GITHUB_WORKSPACE/dist/scrutiny-collector-metrics-${GOOS}-${GOARCH}.exe -tags "static netgo" collector/cmd/collector-metrics/collector-metrics.go - + ls $GITHUB_WORKSPACE/dist/scrutiny-collector-metrics-${GOOS}-${GOARCH}.exe + - name: Release Asset - Collector - windows-amd64 id: upload-release-asset2 uses: actions/upload-release-asset@v1 From 33e370e90fe787119d08e0a78e04856628aac444 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 23 Oct 2021 11:02:14 -0700 Subject: [PATCH 021/114] fix paths. --- .github/workflows/release-windows.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release-windows.yaml b/.github/workflows/release-windows.yaml index 1e01482..e920fb7 100644 --- a/.github/workflows/release-windows.yaml +++ b/.github/workflows/release-windows.yaml @@ -34,12 +34,12 @@ jobs: - name: Build Binaries shell: bash run: | - mkdir -p $GITHUB_WORKSPACE/dist + mkdir -p $GITHUB_WORKSPACE\dist echo "building collector binary (OS = ${GOOS}, ARCH = ${GOARCH})" - go build -ldflags "-extldflags=-static -X main.goos=${GOOS} -X main.goarch=${GOARCH}" -o $GITHUB_WORKSPACE/dist/scrutiny-collector-metrics-${GOOS}-${GOARCH}.exe -tags "static netgo" collector/cmd/collector-metrics/collector-metrics.go - ls $GITHUB_WORKSPACE/dist/scrutiny-collector-metrics-${GOOS}-${GOARCH}.exe - + go build -ldflags "-extldflags=-static -X main.goos=${GOOS} -X main.goarch=${GOARCH}" -o $GITHUB_WORKSPACE\dist\scrutiny-collector-metrics-${GOOS}-${GOARCH}.exe -tags "static netgo" collector\cmd\collector-metrics\collector-metrics.go + ls $GITHUB_WORKSPACE\dist\scrutiny-collector-metrics-${GOOS}-${GOARCH}.exe + - name: Release Asset - Collector - windows-amd64 id: upload-release-asset2 uses: actions/upload-release-asset@v1 From f26dbdf8b68bfbc8ffbe3b9647daaee02382c90b Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 23 Oct 2021 11:02:43 -0700 Subject: [PATCH 022/114] trigger windows binary creation on every release. --- .github/workflows/release-windows.yaml | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/.github/workflows/release-windows.yaml b/.github/workflows/release-windows.yaml index e920fb7..a92ec1e 100644 --- a/.github/workflows/release-windows.yaml +++ b/.github/workflows/release-windows.yaml @@ -6,14 +6,6 @@ on: # Only use the types keyword to narrow down the activity types that will trigger your workflow. types: [published] - # for testing, we can also trigger manually. remove this afterwards. - workflow_dispatch: - inputs: - version_bump_type: - description: 'noop' - required: false - default: 'patch' - jobs: release-windows: @@ -25,9 +17,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 -# TODO: uncomment this -# with: -# ref: ${{github.event.release.tag_name}} + with: + ref: ${{github.event.release.tag_name}} - uses: actions/setup-go@v2 with: go-version: '^1.13.1' # The Go version to download (if necessary) and use. From 0d580932adb3762e13948687217e0247e6554f39 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 23 Oct 2021 12:13:22 -0700 Subject: [PATCH 023/114] fix bumpr --- .github/workflows/release.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f7f9e1c..9a97b40 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -34,7 +34,8 @@ jobs: with: version_bump_type: ${{ github.event.inputs.version_bump_type }} version_metadata_path: ${{ github.event.inputs.version_metadata_path }} - github_token: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} # Leave this line unchanged - name: Test run: | mkdir -p $(dirname "$PROJECT_PATH") From 0460985bc508ca6c9cc82e20d197382a4aed6996 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 23 Oct 2021 12:28:30 -0700 Subject: [PATCH 024/114] fix windows asset builder --- .github/workflows/release-windows.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release-windows.yaml b/.github/workflows/release-windows.yaml index a92ec1e..6a675bd 100644 --- a/.github/workflows/release-windows.yaml +++ b/.github/workflows/release-windows.yaml @@ -25,11 +25,11 @@ jobs: - name: Build Binaries shell: bash run: | - mkdir -p $GITHUB_WORKSPACE\dist + mkdir -p $GITHUB_WORKSPACE/dist echo "building collector binary (OS = ${GOOS}, ARCH = ${GOARCH})" - go build -ldflags "-extldflags=-static -X main.goos=${GOOS} -X main.goarch=${GOARCH}" -o $GITHUB_WORKSPACE\dist\scrutiny-collector-metrics-${GOOS}-${GOARCH}.exe -tags "static netgo" collector\cmd\collector-metrics\collector-metrics.go - ls $GITHUB_WORKSPACE\dist\scrutiny-collector-metrics-${GOOS}-${GOARCH}.exe + go build -ldflags "-extldflags=-static -X main.goos=${GOOS} -X main.goarch=${GOARCH}" -o $GITHUB_WORKSPACE/dist/scrutiny-collector-metrics-${GOOS}-${GOARCH}.exe -tags "static netgo" collector/cmd/collector-metrics/collector-metrics.go + ls $GITHUB_WORKSPACE/dist/scrutiny-collector-metrics-${GOOS}-${GOARCH}.exe - name: Release Asset - Collector - windows-amd64 id: upload-release-asset2 @@ -38,6 +38,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: './dist/scrutiny-collector-metrics-windows-amd64' - asset_name: scrutiny-collector-metrics-windows-amd64 + asset_path: './dist/scrutiny-collector-metrics-windows-amd64.exe' + asset_name: scrutiny-collector-metrics-windows-amd64.exe asset_content_type: application/octet-stream From 5880e0af86891f39441de998ce5d8f547db94f28 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 23 Oct 2021 12:46:45 -0700 Subject: [PATCH 025/114] using packagr actions for publishing artifacts. --- .github/workflows/release.yaml | 223 ++++++++++++++------------------- 1 file changed, 97 insertions(+), 126 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 9a97b40..a6393d1 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -51,154 +51,125 @@ jobs: cd $PROJECT_PATH make all - - name: Commit - uses: EndBug/add-and-commit@v4 # You can change this to use a specific version - with: - - author_name: Jason Kulatunga - author_email: jason@thesparktree.com - cwd: ${{ env.PROJECT_PATH }} - force: false - signoff: true - message: '(${{steps.bump_version.outputs.release_version}}) Automated packaging of release by Packagr' - tag: ${{steps.bump_version.outputs.release_version}} + - name: Commit Changes + id: commit + uses: packagrio/action-releasr-go@master env: + # This is necessary in order to push a commit to the repo GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} # Leave this line unchanged - - name: Create Release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - tag_name: ${{ steps.bump_version.outputs.release_version }} - release_name: Release ${{ steps.bump_version.outputs.release_version }} - draft: false - prerelease: false - - - name: Release Asset - Web - linux-amd64 - id: upload-release-asset1 - uses: actions/upload-release-asset@v1 + - name: Publish Release + id: publish + uses: packagrio/action-publishr-go@master env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-web-linux-amd64 - asset_name: scrutiny-web-linux-amd64 - asset_content_type: application/octet-stream - - name: Release Asset - Collector - linux-amd64 - id: upload-release-asset2 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + # This is necessary in order to push a commit to the repo + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} # Leave this line unchanged with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-collector-metrics-linux-amd64 - asset_name: scrutiny-collector-metrics-linux-amd64 - asset_content_type: application/octet-stream + upload_assets: '/build/scrutiny-web-linux-amd64 /build/scrutiny-collector-metrics-linux-amd64 /build/scrutiny-web-linux-arm64 /build/scrutiny-collector-metrics-linux-arm64 /build/scrutiny-web-linux-arm-5 /build/scrutiny-collector-metrics-linux-arm-5 /build/scrutiny-web-linux-arm-6 /build/scrutiny-collector-metrics-linux-arm-6 /build/scrutiny-web-linux-arm-7 /build/scrutiny-collector-metrics-linux-arm-7' - - name: Release Asset - Web - linux-arm64 - id: upload-release-asset3 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-web-linux-arm64 - asset_name: scrutiny-web-linux-arm64 - asset_content_type: application/octet-stream - - name: Release Asset - Collector - linux-arm64 - id: upload-release-asset4 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-collector-metrics-linux-arm64 - asset_name: scrutiny-collector-metrics-linux-arm64 - asset_content_type: application/octet-stream +# - name: Release Asset - Web - linux-amd64 +# id: upload-release-asset1 +# uses: actions/upload-release-asset@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} +# with: +# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps +# asset_path: /build/scrutiny-web-linux-amd64 +# asset_name: scrutiny-web-linux-amd64 +# asset_content_type: application/octet-stream +# - name: Release Asset - Collector - linux-amd64 +# id: upload-release-asset2 +# uses: actions/upload-release-asset@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} +# with: +# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps +# asset_path: /build/scrutiny-collector-metrics-linux-amd64 +# asset_name: scrutiny-collector-metrics-linux-amd64 +# asset_content_type: application/octet-stream - - name: Release Asset - Web - linux-arm-5 - id: upload-release-asset5 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-web-linux-arm-5 - asset_name: scrutiny-web-linux-arm-5 - asset_content_type: application/octet-stream - - name: Release Asset - Collector - linux-arm-5 - id: upload-release-asset6 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-collector-metrics-linux-arm-5 - asset_name: scrutiny-collector-metrics-linux-arm-5 - asset_content_type: application/octet-stream - - name: Release Asset - Web - linux-arm-6 - id: upload-release-asset7 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-web-linux-arm-6 - asset_name: scrutiny-web-linux-arm-6 - asset_content_type: application/octet-stream - - name: Release Asset - Collector - linux-arm-6 - id: upload-release-asset8 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-collector-metrics-linux-arm-6 - asset_name: scrutiny-collector-metrics-linux-arm-6 - asset_content_type: application/octet-stream +# - name: Release Asset - Web - linux-arm64 +# id: upload-release-asset3 +# uses: actions/upload-release-asset@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} +# with: +# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps +# asset_path: /build/scrutiny-web-linux-arm64 +# asset_name: scrutiny-web-linux-arm64 +# asset_content_type: application/octet-stream +# - name: Release Asset - Collector - linux-arm64 +# id: upload-release-asset4 +# uses: actions/upload-release-asset@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} +# with: +# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps +# asset_path: /build/scrutiny-collector-metrics-linux-arm64 +# asset_name: scrutiny-collector-metrics-linux-arm64 +# asset_content_type: application/octet-stream - - name: Release Asset - Web - linux-arm-7 - id: upload-release-asset9 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-web-linux-arm-7 - asset_name: scrutiny-web-linux-arm-7 - asset_content_type: application/octet-stream - - name: Release Asset - Collector - linux-arm-7 - id: upload-release-asset10 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-collector-metrics-linux-arm-7 - asset_name: scrutiny-collector-metrics-linux-arm-7 - asset_content_type: application/octet-stream +# - name: Release Asset - Web - linux-arm-5 +# id: upload-release-asset5 +# uses: actions/upload-release-asset@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} +# with: +# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps +# asset_path: /build/scrutiny-web-linux-arm-5 +# asset_name: scrutiny-web-linux-arm-5 +# asset_content_type: application/octet-stream +# - name: Release Asset - Collector - linux-arm-5 +# id: upload-release-asset6 +# uses: actions/upload-release-asset@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} +# with: +# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps +# asset_path: /build/scrutiny-collector-metrics-linux-arm-5 +# asset_name: scrutiny-collector-metrics-linux-arm-5 +# asset_content_type: application/octet-stream -# - name: Release Asset - Web - freebsd-amd64 +# - name: Release Asset - Web - linux-arm-6 # id: upload-release-asset7 # uses: actions/upload-release-asset@v1 # env: # GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} # with: # upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: ${{ env.PROJECT_PATH }}/scrutiny-web-freebsd-amd64 -# asset_name: scrutiny-web-freebsd-amd64 +# asset_path: /build/scrutiny-web-linux-arm-6 +# asset_name: scrutiny-web-linux-arm-6 # asset_content_type: application/octet-stream -# - name: Release Asset - Collector - freebsd-amd64 +# - name: Release Asset - Collector - linux-arm-6 # id: upload-release-asset8 # uses: actions/upload-release-asset@v1 # env: # GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} # with: # upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: ${{ env.PROJECT_PATH }}/scrutiny-collector-metrics-freebsd-amd64 -# asset_name: scrutiny-collector-metrics-freebsd-amd64 +# asset_path: /build/scrutiny-collector-metrics-linux-arm-6 +# asset_name: scrutiny-collector-metrics-linux-arm-6 +# asset_content_type: application/octet-stream + +# - name: Release Asset - Web - linux-arm-7 +# id: upload-release-asset9 +# uses: actions/upload-release-asset@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} +# with: +# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps +# asset_path: /build/scrutiny-web-linux-arm-7 +# asset_name: scrutiny-web-linux-arm-7 +# asset_content_type: application/octet-stream +# - name: Release Asset - Collector - linux-arm-7 +# id: upload-release-asset10 +# uses: actions/upload-release-asset@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} +# with: +# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps +# asset_path: /build/scrutiny-collector-metrics-linux-arm-7 +# asset_name: scrutiny-collector-metrics-linux-arm-7 # asset_content_type: application/octet-stream From d346a394e6917a2a7db7416233c1b660e8accfb4 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 23 Oct 2021 12:57:59 -0700 Subject: [PATCH 026/114] fixing packagr actions for publishing artifacts. --- .github/workflows/release.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a6393d1..bc01456 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -57,7 +57,8 @@ jobs: env: # This is necessary in order to push a commit to the repo GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} # Leave this line unchanged - + with: + version_metadata_path: ${{ github.event.inputs.version_metadata_path }} - name: Publish Release id: publish uses: packagrio/action-publishr-go@master From 315b43ea051ebd97832663eefddab6055893cc4a Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 23 Oct 2021 16:49:26 -0700 Subject: [PATCH 027/114] fixing packagr actions for publishing artifacts. --- .github/workflows/release.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index bc01456..ecbf838 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -51,6 +51,9 @@ jobs: cd $PROJECT_PATH make all + # restore modified dir to GH workspace. + cp -arf $PROJECT_PATH/. $GITHUB_WORKSPACE/ + - name: Commit Changes id: commit uses: packagrio/action-releasr-go@master From fe3f38ae54163b2c5b43c1d88fc08b7631a7655a Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 23 Oct 2021 17:03:31 -0700 Subject: [PATCH 028/114] fixing packagr actions for publishing artifacts. --- .github/workflows/release.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ecbf838..1b830ea 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -28,6 +28,8 @@ jobs: git --version - name: Checkout uses: actions/checkout@v2 + with: + fetch-depth: 0 - name: Bump version id: bump_version uses: packagrio/action-bumpr-go@master From 9878985fa3393525cb437b8c25536897bf4c4f6e Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 24 Oct 2021 13:07:12 -0700 Subject: [PATCH 029/114] adding aggregation code --- CONTRIBUTING.md | 7 +- go.mod | 2 +- .../pkg/database/scrutiny_repository.go | 142 ++- .../pkg/models/testdata/smart-ata-date2.json | 846 ++++++++++++++++++ 4 files changed, 979 insertions(+), 18 deletions(-) create mode 100644 webapp/backend/pkg/models/testdata/smart-ata-date2.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 034d407..8e4f34b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -79,9 +79,9 @@ docker run -p 8086:8086 --rm influxdb:2.0 docker run -p 8086:8086 \ -e DOCKER_INFLUXDB_INIT_USERNAME=admin \ - -e DOCKER_INFLUXDB_INIT_PASSWORD=12345678 \ - -e DOCKER_INFLUXDB_INIT_ORG=my-org \ - -e DOCKER_INFLUXDB_INIT_BUCKET=bucket \ + -e DOCKER_INFLUXDB_INIT_PASSWORD=password12345 \ + -e DOCKER_INFLUXDB_INIT_ORG=scrutiny \ + -e DOCKER_INFLUXDB_INIT_BUCKET=metrics \ influxdb:2.0 @@ -89,6 +89,7 @@ curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/web/test curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-ata.json localhost:8080/api/device/0x5000cca264eb01d7/smart curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-ata-date.json localhost:8080/api/device/0x5000cca264eb01d7/smart +curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-ata-date2.json localhost:8080/api/device/0x5000cca264eb01d7/smart curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-fail2.json localhost:8080/api/device/0x5000cca264ec3183/smart curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-nvme.json localhost:8080/api/device/0x5002538e40a22954/smart curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-scsi.json localhost:8080/api/device/0x5000cca252c859cc/smart diff --git a/go.mod b/go.mod index d8d1baf..1f4714d 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/gin-gonic/gin v1.6.3 github.com/golang/mock v1.4.3 github.com/google/uuid v1.2.0 // indirect - github.com/hashicorp/serf v0.8.2 + github.com/hashicorp/serf v0.8.2 // indirect github.com/influxdata/influxdb-client-go/v2 v2.2.3 github.com/jaypipes/ghw v0.6.1 github.com/klauspost/compress v1.12.1 // indirect diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index 885afb9..bac613b 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -10,6 +10,7 @@ import ( "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" influxdb2 "github.com/influxdata/influxdb-client-go/v2" "github.com/influxdata/influxdb-client-go/v2/api" + "github.com/influxdata/influxdb-client-go/v2/domain" "github.com/sirupsen/logrus" "gorm.io/driver/sqlite" "gorm.io/gorm" @@ -39,6 +40,7 @@ import ( //} func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.FieldLogger) (DeviceRepo, error) { + backgroundContext := context.Background() //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Gorm/SQLite setup @@ -70,19 +72,49 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field // if no token is provided, but we have a valid server, we're going to assume this is the first setup of our server. // we will initialize with a predetermined username & password, that you should change. + + // metrics bucket will have a retention period of 8 days (since it will be down-sampled once a week) + // in hours (24hours * 8 days) = 192 onboardingResponse, err := client.Setup( - context.Background(), + backgroundContext, appConfig.GetString("web.influxdb.init_username"), appConfig.GetString("web.influxdb.init_password"), appConfig.GetString("web.influxdb.org"), appConfig.GetString("web.influxdb.bucket"), - 0) + 192) if err != nil { return nil, err } appConfig.Set("web.influxdb.token", *onboardingResponse.Auth.Token) //todo: determine if we should write the config file out here. + + orgId, err := client.OrganizationsAPI().FindOrganizationByID(backgroundContext, appConfig.GetString("web.influxdb.org")) + if err != nil { + return nil, err + } + + //create buckets (used for downsampling) + + // metrics_weekly bucket will have a retention period of 8+1 weeks (since it will be down-sampled once a month) + // in seconds (60seconds * 60minutes * 24hours * 7 days * 9 weeks) = 5_443_200 + _, err = client.BucketsAPI().CreateBucketWithName(backgroundContext, orgId, fmt.Sprintf("%s_weekly", appConfig.GetString("web.influxdb.bucket")), domain.RetentionRule{EverySeconds: 5_443_200}) + if err != nil { + return nil, err + } + + // metrics_monthly bucket will have a retention period of 24+1 months (since it will be down-sampled once a year) + // in seconds (60seconds * 60minutes * 24hours * 7 days * (52 + 52 + 4)weeks) = 65_318_400 + _, err = client.BucketsAPI().CreateBucketWithName(backgroundContext, orgId, fmt.Sprintf("%s_monthly", appConfig.GetString("web.influxdb.bucket")), domain.RetentionRule{EverySeconds: 65_318_400}) + if err != nil { + return nil, err + } + + // metrics_yearly bucket will have an infinite retention period + _, err = client.BucketsAPI().CreateBucketWithName(backgroundContext, orgId, fmt.Sprintf("%s_yearly", appConfig.GetString("web.influxdb.bucket"))) + if err != nil { + return nil, err + } } // Use blocking write client for writes to desired bucket @@ -104,10 +136,14 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field influxClient: client, influxWriteApi: writeAPI, influxQueryApi: queryAPI, - influxTaskApi: taskAPI, + influxTaskApi: taskAPI, gormClient: database, } - + // Initialize Background Tasks + err = deviceRepo.InitTasks(backgroundContext) + if err != nil { + return nil, err + } return &deviceRepo, nil } @@ -117,7 +153,7 @@ type scrutinyRepository struct { influxWriteApi api.WriteAPIBlocking influxQueryApi api.QueryAPI - influxTaskApi api.TasksAPI + influxTaskApi api.TasksAPI influxClient influxdb2.Client gormClient *gorm.DB @@ -132,20 +168,98 @@ func (sr *scrutinyRepository) Close() error { // Tasks //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// func (sr *scrutinyRepository) InitTasks(ctx context.Context) error { - flux := "" - - //weekly on Sunday at 1:00am - sr.influxTaskApi.CreateTaskWithCron(ctx, "tsk-weekly-aggr", flux, "0 1 * * 0", sr.appConfig.GetString("web.influxdb.org")) + weeklyTaskName := "tsk-weekly-aggr" + if _, missingTask := sr.influxTaskApi.GetTaskByID(ctx, weeklyTaskName); missingTask != nil { + //weekly on Sunday at 1:00am + _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, weeklyTaskName, sr.DownsampleScript("weekly"), "0 1 * * 0", sr.appConfig.GetString("web.influxdb.org")) + if err != nil { + return err + } + } - //monthly on first day of the month at 1:30am - sr.influxTaskApi.CreateTaskWithCron(ctx, "tsk-monthly-aggr", flux, "30 1 1 * *", sr.appConfig.GetString("web.influxdb.org")) + monthlyTaskName := "tsk-monthly-aggr" + if _, missingTask := sr.influxTaskApi.GetTaskByID(ctx, monthlyTaskName); missingTask != nil { + //monthly on first day of the month at 1:30am + _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, monthlyTaskName, sr.DownsampleScript("monthly"), "30 1 1 * *", sr.appConfig.GetString("web.influxdb.org")) + if err != nil { + return err + } + } - //yearly on the frist day of the year at 2:00am - sr.influxTaskApi.CreateTaskWithCron(ctx, "tsk-yearly-aggr", flux, "0 2 1 1 *", sr.appConfig.GetString("web.influxdb.org")) + yearlyTaskName := "tsk-monthly-aggr" + if _, missingTask := sr.influxTaskApi.GetTaskByID(ctx, yearlyTaskName); missingTask != nil { + //yearly on the first day of the year at 2:00am + _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, yearlyTaskName, sr.DownsampleScript("yearly"), "0 2 1 1 *", sr.appConfig.GetString("web.influxdb.org")) + if err != nil { + return err + } + } + return nil } -func (sr *scrutinyRepository) DownsampleScript(aggregate string) (string, error){ +func (sr *scrutinyRepository) DownsampleScript(aggregationType string) string { + var sourceBucket string // the source of the data + var destBucket string // the destination for the aggregated data + var rangeStart string + var rangeEnd string + var aggWindow string + switch aggregationType { + case "weekly": + sourceBucket = sr.appConfig.GetString("web.influxdb.bucket") + destBucket = fmt.Sprintf("%s_weekly", sr.appConfig.GetString("web.influxdb.bucket")) + rangeStart = "-2w" + rangeEnd = "-1w" + aggWindow = "1w" + case "monthly": + sourceBucket = fmt.Sprintf("%s_weekly", sr.appConfig.GetString("web.influxdb.bucket")) + destBucket = fmt.Sprintf("%s_monthly", sr.appConfig.GetString("web.influxdb.bucket")) + rangeStart = "-2mo" + rangeEnd = "-1mo" + aggWindow = "1mo" + case "yearly": + sourceBucket = fmt.Sprintf("%s_monthly", sr.appConfig.GetString("web.influxdb.bucket")) + destBucket = fmt.Sprintf("%s_yearly", sr.appConfig.GetString("web.influxdb.bucket")) + rangeStart = "-2y" + rangeEnd = "-1y" + aggWindow = "1y" + } + + return fmt.Sprintf(` + sourceBucket = "%s" + rangeStart = %s + rangeEnd = %s + aggWindow = %s + destBucket = "%s" + destOrg = "%s" + + smart_data = from(bucket: sourceBucket) + |> range(start: rangeStart, stop: rangeEnd) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> filter(fn: (r) => r["_field"] !~ /(raw_string|_measurement|device_protocol|device_wwn|attribute_id|name|status|when_failed)/) + |> last() + |> yield(name: "last") + + smart_data + |> aggregateWindow(fn: mean, every: aggWindow) + |> to(bucket: destBucket, org: destOrg) + + temp_data = from(bucket: sourceBucket) + |> range(start: rangeStart, stop: rangeEnd) + |> filter(fn: (r) => r["_measurement"] == "temp") + |> last() + |> yield(name: "mean") + temp_data + |> aggregateWindow(fn: mean, every: aggWindow) + |> to(bucket: destBucket, org: destOrg) + `, + sourceBucket, + rangeStart, + rangeEnd, + aggWindow, + destBucket, + sr.appConfig.GetString("web.influxdb.org"), + ) } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/webapp/backend/pkg/models/testdata/smart-ata-date2.json b/webapp/backend/pkg/models/testdata/smart-ata-date2.json new file mode 100644 index 0000000..78ca0f9 --- /dev/null +++ b/webapp/backend/pkg/models/testdata/smart-ata-date2.json @@ -0,0 +1,846 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 0 + ], + "svn_revision": "4883", + "platform_info": "x86_64-linux-4.19.128-flatcar", + "build_info": "(local build)", + "argv": [ + "smartctl", + "-j", + "-a", + "/dev/sdb" + ], + "exit_status": 0 + }, + "device": { + "name": "/dev/sdb", + "info_name": "/dev/sdb [SAT]", + "type": "sat", + "protocol": "ATA" + }, + "model_name": "WDC WD140EDFZ-11A0VA0", + "serial_number": "9RK1XXXX", + "wwn": { + "naa": 5, + "oui": 3274, + "id": 10283057623 + }, + "firmware_version": "81.00A81", + "user_capacity": { + "blocks": 27344764928, + "bytes": 14000519643136 + }, + "logical_block_size": 512, + "physical_block_size": 4096, + "rotation_rate": 5400, + "form_factor": { + "ata_value": 2, + "name": "3.5 inches" + }, + "in_smartctl_database": false, + "ata_version": { + "string": "ACS-2, ATA8-ACS T13/1699-D revision 4", + "major_value": 1020, + "minor_value": 41 + }, + "sata_version": { + "string": "SATA 3.2", + "value": 255 + }, + "interface_speed": { + "max": { + "sata_value": 14, + "string": "6.0 Gb/s", + "units_per_second": 60, + "bits_per_unit": 100000000 + }, + "current": { + "sata_value": 3, + "string": "6.0 Gb/s", + "units_per_second": 60, + "bits_per_unit": 100000000 + } + }, + "local_time": { + "time_t": 1614101651, + "asctime": "Tue Feb 23 00:03:30 2021 UTC" + }, + "smart_status": { + "passed": true + }, + "ata_smart_data": { + "offline_data_collection": { + "status": { + "value": 130, + "string": "was completed without error", + "passed": true + }, + "completion_seconds": 101 + }, + "self_test": { + "status": { + "value": 241, + "string": "in progress, 10% remaining", + "remaining_percent": 10 + }, + "polling_minutes": { + "short": 2, + "extended": 1479 + } + }, + "capabilities": { + "values": [ + 91, + 3 + ], + "exec_offline_immediate_supported": true, + "offline_is_aborted_upon_new_cmd": false, + "offline_surface_scan_supported": true, + "self_tests_supported": true, + "conveyance_self_test_supported": false, + "selective_self_test_supported": true, + "attribute_autosave_enabled": true, + "error_logging_supported": true, + "gp_logging_supported": true + } + }, + "ata_sct_capabilities": { + "value": 61, + "error_recovery_control_supported": true, + "feature_control_supported": true, + "data_table_supported": true + }, + "ata_smart_attributes": { + "revision": 16, + "table": [ + { + "id": 1, + "name": "Raw_Read_Error_Rate", + "value": 90, + "worst": 100, + "thresh": 1, + "when_failed": "", + "flags": { + "value": 11, + "string": "PO-R-- ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": true, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 10, + "string": "0" + } + }, + { + "id": 2, + "name": "Throughput_Performance", + "value": 125, + "worst": 135, + "thresh": 54, + "when_failed": "", + "flags": { + "value": 4, + "string": "--S--- ", + "prefailure": false, + "updated_online": false, + "performance": true, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 118, + "string": "108" + } + }, + { + "id": 3, + "name": "Spin_Up_Time", + "value": 71, + "worst": 81, + "thresh": 1, + "when_failed": "", + "flags": { + "value": 7, + "string": "POS--- ", + "prefailure": true, + "updated_online": true, + "performance": true, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 30089675142, + "string": "380 (Average 380)" + } + }, + { + "id": 4, + "name": "Start_Stop_Count", + "value": 90, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 18, + "string": "-O--C- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 19, + "string": "9" + } + }, + { + "id": 5, + "name": "Reallocated_Sector_Ct", + "value": 90, + "worst": 100, + "thresh": 1, + "when_failed": "", + "flags": { + "value": 51, + "string": "PO--CK ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 10, + "string": "0" + } + }, + { + "id": 7, + "name": "Seek_Error_Rate", + "value": 90, + "worst": 100, + "thresh": 1, + "when_failed": "", + "flags": { + "value": 10, + "string": "-O-R-- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": true, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 10, + "string": "0" + } + }, + { + "id": 8, + "name": "Seek_Time_Performance", + "value": 123, + "worst": 133, + "thresh": 20, + "when_failed": "", + "flags": { + "value": 4, + "string": "--S--- ", + "prefailure": false, + "updated_online": false, + "performance": true, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 28, + "string": "18" + } + }, + { + "id": 9, + "name": "Power_On_Hours", + "value": 90, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 18, + "string": "-O--C- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 1740, + "string": "1730" + } + }, + { + "id": 10, + "name": "Spin_Retry_Count", + "value": 90, + "worst": 100, + "thresh": 1, + "when_failed": "", + "flags": { + "value": 18, + "string": "-O--C- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 10, + "string": "0" + } + }, + { + "id": 12, + "name": "Power_Cycle_Count", + "value": 90, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 19, + "string": "9" + } + }, + { + "id": 22, + "name": "Unknown_Attribute", + "value": 90, + "worst": 100, + "thresh": 25, + "when_failed": "", + "flags": { + "value": 35, + "string": "PO---K ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": true + }, + "raw": { + "value": 110, + "string": "100" + } + }, + { + "id": 192, + "name": "Power-Off_Retract_Count", + "value": 90, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 339, + "string": "329" + } + }, + { + "id": 193, + "name": "Load_Cycle_Count", + "value": 90, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 18, + "string": "-O--C- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 339, + "string": "329" + } + }, + { + "id": 194, + "name": "Temperature_Celsius", + "value": 41, + "worst": 51, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 2, + "string": "-O---- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 163210330154, + "string": "32 (Min/Max 24/38)" + } + }, + { + "id": 196, + "name": "Reallocated_Event_Count", + "value": 90, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 10, + "string": "0" + } + }, + { + "id": 197, + "name": "Current_Pending_Sector", + "value": 90, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 34, + "string": "-O---K ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": true + }, + "raw": { + "value": 10, + "string": "0" + } + }, + { + "id": 198, + "name": "Offline_Uncorrectable", + "value": 90, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 8, + "string": "---R-- ", + "prefailure": false, + "updated_online": false, + "performance": false, + "error_rate": true, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 10, + "string": "0" + } + }, + { + "id": 199, + "name": "UDMA_CRC_Error_Count", + "value": 90, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 10, + "string": "-O-R-- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": true, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 10, + "string": "0" + } + } + ] + }, + "power_on_time": { + "hours": 3030 + }, + "power_cycle_count": 9, + "temperature": { + "current": 62 + }, + "ata_smart_error_log": { + "summary": { + "revision": 1, + "count": 0 + } + }, + "ata_smart_self_test_log": { + "standard": { + "revision": 1, + "table": [ + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1708 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1684 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1661 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1636 + }, + { + "type": { + "value": 2, + "string": "Extended offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1624 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1541 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1517 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1493 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1469 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1445 + }, + { + "type": { + "value": 2, + "string": "Extended offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1439 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1373 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1349 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1325 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1301 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1277 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1253 + }, + { + "type": { + "value": 2, + "string": "Extended offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1252 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1205 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1181 + }, + { + "type": { + "value": 1, + "string": "Short offline" + }, + "status": { + "value": 0, + "string": "Completed without error", + "passed": true + }, + "lifetime_hours": 1157 + } + ], + "count": 21, + "error_count_total": 0, + "error_count_outdated": 0 + } + }, + "ata_smart_selective_self_test_log": { + "revision": 1, + "table": [ + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 241, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 241, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 241, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 241, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 241, + "string": "Not_testing" + } + } + ], + "flags": { + "value": 0, + "remainder_scan_enabled": false + }, + "power_up_scan_resume_minutes": 0 + } +} From 31b5dfa038bfe522140dfa56b3ec172ba0b00661 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 24 Oct 2021 16:01:53 -0700 Subject: [PATCH 030/114] ensure that all buckets are created during init. Remove all references to "name" field for attributes (shoudl come from metadata instead). Status is now an int64 (0 is passing). --- webapp/backend/pkg/constants.go | 6 +- .../pkg/database/scrutiny_repository.go | 112 ++++++++++++------ .../backend/pkg/models/measurements/smart.go | 60 +++++----- .../measurements/smart_ata_attribute.go | 14 +-- .../models/measurements/smart_attribute.go | 2 +- .../measurements/smart_nvme_attribute.go | 14 +-- .../measurements/smart_scsci_attribute.go | 14 +-- .../pkg/thresholds/ata_attribute_metadata.go | 2 +- 8 files changed, 116 insertions(+), 108 deletions(-) diff --git a/webapp/backend/pkg/constants.go b/webapp/backend/pkg/constants.go index 83ab99b..abccc06 100644 --- a/webapp/backend/pkg/constants.go +++ b/webapp/backend/pkg/constants.go @@ -4,9 +4,9 @@ const DeviceProtocolAta = "ATA" const DeviceProtocolScsi = "SCSI" const DeviceProtocolNvme = "NVMe" -const SmartAttributeStatusPassed = "passed" -const SmartAttributeStatusFailed = "failed" -const SmartAttributeStatusWarning = "warn" +const SmartAttributeStatusPassed = 0 +const SmartAttributeStatusFailed = 1 +const SmartAttributeStatusWarning = 2 const SmartWhenFailedFailingNow = "FAILING_NOW" const SmartWhenFailedInThePast = "IN_THE_PAST" diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index bac613b..0ff4a36 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -74,47 +74,20 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field // we will initialize with a predetermined username & password, that you should change. // metrics bucket will have a retention period of 8 days (since it will be down-sampled once a week) - // in hours (24hours * 8 days) = 192 + // in seconds (60seconds * 60minutes * 24hours * 15 days) = 1_296_000 (see EnsureBucket() function) onboardingResponse, err := client.Setup( backgroundContext, appConfig.GetString("web.influxdb.init_username"), appConfig.GetString("web.influxdb.init_password"), appConfig.GetString("web.influxdb.org"), appConfig.GetString("web.influxdb.bucket"), - 192) + 0) if err != nil { return nil, err } appConfig.Set("web.influxdb.token", *onboardingResponse.Auth.Token) //todo: determine if we should write the config file out here. - - orgId, err := client.OrganizationsAPI().FindOrganizationByID(backgroundContext, appConfig.GetString("web.influxdb.org")) - if err != nil { - return nil, err - } - - //create buckets (used for downsampling) - - // metrics_weekly bucket will have a retention period of 8+1 weeks (since it will be down-sampled once a month) - // in seconds (60seconds * 60minutes * 24hours * 7 days * 9 weeks) = 5_443_200 - _, err = client.BucketsAPI().CreateBucketWithName(backgroundContext, orgId, fmt.Sprintf("%s_weekly", appConfig.GetString("web.influxdb.bucket")), domain.RetentionRule{EverySeconds: 5_443_200}) - if err != nil { - return nil, err - } - - // metrics_monthly bucket will have a retention period of 24+1 months (since it will be down-sampled once a year) - // in seconds (60seconds * 60minutes * 24hours * 7 days * (52 + 52 + 4)weeks) = 65_318_400 - _, err = client.BucketsAPI().CreateBucketWithName(backgroundContext, orgId, fmt.Sprintf("%s_monthly", appConfig.GetString("web.influxdb.bucket")), domain.RetentionRule{EverySeconds: 65_318_400}) - if err != nil { - return nil, err - } - - // metrics_yearly bucket will have an infinite retention period - _, err = client.BucketsAPI().CreateBucketWithName(backgroundContext, orgId, fmt.Sprintf("%s_yearly", appConfig.GetString("web.influxdb.bucket"))) - if err != nil { - return nil, err - } } // Use blocking write client for writes to desired bucket @@ -139,8 +112,20 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field influxTaskApi: taskAPI, gormClient: database, } + + orgInfo, err := client.OrganizationsAPI().FindOrganizationByName(backgroundContext, appConfig.GetString("web.influxdb.org")) + if err != nil { + return nil, err + } + + // Initialize Buckets (if necessary) + err = deviceRepo.EnsureBuckets(backgroundContext, orgInfo) + if err != nil { + return nil, err + } + // Initialize Background Tasks - err = deviceRepo.InitTasks(backgroundContext) + err = deviceRepo.EnsureTasks(backgroundContext, *orgInfo.Id) if err != nil { return nil, err } @@ -164,32 +149,81 @@ func (sr *scrutinyRepository) Close() error { return nil } +func (sr *scrutinyRepository) EnsureBuckets(ctx context.Context, org *domain.Organization) error { + + mainBucket := sr.appConfig.GetString("web.influxdb.bucket") + if foundMainBucket, foundErr := sr.influxClient.BucketsAPI().FindBucketByName(ctx, mainBucket); foundErr != nil { + // metrics bucket will have a retention period of (14+1) 15 days (since it will be down-sampled once a week) + // in seconds (60seconds * 60minutes * 24hours * 15 days) = 1_296_000 + _, err := sr.influxClient.BucketsAPI().CreateBucketWithName(ctx, org, mainBucket, domain.RetentionRule{EverySeconds: 1_296_000}) + if err != nil { + return err + } + } else { + //correctly set the retention period for the main bucket (cant do it during creation) + foundMainBucket.RetentionRules = domain.RetentionRules{domain.RetentionRule{EverySeconds: 1_296_000}} + sr.influxClient.BucketsAPI().UpdateBucket(ctx, foundMainBucket) + } + + //create buckets (used for downsampling) + weeklyBucket := fmt.Sprintf("%s_weekly", sr.appConfig.GetString("web.influxdb.bucket")) + if _, foundErr := sr.influxClient.BucketsAPI().FindBucketByName(ctx, weeklyBucket); foundErr != nil { + // metrics_weekly bucket will have a retention period of 8+1 weeks (since it will be down-sampled once a month) + // in seconds (60seconds * 60minutes * 24hours * 7 days * 9 weeks) = 5_443_200 + _, err := sr.influxClient.BucketsAPI().CreateBucketWithName(ctx, org, weeklyBucket, domain.RetentionRule{EverySeconds: 5_443_200}) + if err != nil { + return err + } + } + + monthlyBucket := fmt.Sprintf("%s_monthly", sr.appConfig.GetString("web.influxdb.bucket")) + if _, foundErr := sr.influxClient.BucketsAPI().FindBucketByName(ctx, monthlyBucket); foundErr != nil { + // metrics_monthly bucket will have a retention period of 24+1 months (since it will be down-sampled once a year) + // in seconds (60seconds * 60minutes * 24hours * 7 days * (52 + 52 + 4)weeks) = 65_318_400 + _, err := sr.influxClient.BucketsAPI().CreateBucketWithName(ctx, org, monthlyBucket, domain.RetentionRule{EverySeconds: 65_318_400}) + if err != nil { + return err + } + } + + yearlyBucket := fmt.Sprintf("%s_yearly", sr.appConfig.GetString("web.influxdb.bucket")) + if _, foundErr := sr.influxClient.BucketsAPI().FindBucketByName(ctx, yearlyBucket); foundErr != nil { + // metrics_yearly bucket will have an infinite retention period + _, err := sr.influxClient.BucketsAPI().CreateBucketWithName(ctx, org, yearlyBucket) + if err != nil { + return err + } + } + + return nil +} + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Tasks //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -func (sr *scrutinyRepository) InitTasks(ctx context.Context) error { +func (sr *scrutinyRepository) EnsureTasks(ctx context.Context, orgID string) error { weeklyTaskName := "tsk-weekly-aggr" - if _, missingTask := sr.influxTaskApi.GetTaskByID(ctx, weeklyTaskName); missingTask != nil { + if found, findErr := sr.influxTaskApi.FindTasks(ctx, &api.TaskFilter{Name: weeklyTaskName}); findErr == nil && len(found) == 0 { //weekly on Sunday at 1:00am - _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, weeklyTaskName, sr.DownsampleScript("weekly"), "0 1 * * 0", sr.appConfig.GetString("web.influxdb.org")) + _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, weeklyTaskName, sr.DownsampleScript("weekly"), "0 1 * * 0", orgID) if err != nil { return err } } monthlyTaskName := "tsk-monthly-aggr" - if _, missingTask := sr.influxTaskApi.GetTaskByID(ctx, monthlyTaskName); missingTask != nil { + if found, findErr := sr.influxTaskApi.FindTasks(ctx, &api.TaskFilter{Name: monthlyTaskName}); findErr == nil && len(found) == 0 { //monthly on first day of the month at 1:30am - _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, monthlyTaskName, sr.DownsampleScript("monthly"), "30 1 1 * *", sr.appConfig.GetString("web.influxdb.org")) + _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, monthlyTaskName, sr.DownsampleScript("monthly"), "30 1 1 * *", orgID) if err != nil { return err } } - yearlyTaskName := "tsk-monthly-aggr" - if _, missingTask := sr.influxTaskApi.GetTaskByID(ctx, yearlyTaskName); missingTask != nil { + yearlyTaskName := "tsk-yearly-aggr" + if found, findErr := sr.influxTaskApi.FindTasks(ctx, &api.TaskFilter{Name: yearlyTaskName}); findErr == nil && len(found) == 0 { //yearly on the first day of the year at 2:00am - _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, yearlyTaskName, sr.DownsampleScript("yearly"), "0 2 1 1 *", sr.appConfig.GetString("web.influxdb.org")) + _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, yearlyTaskName, sr.DownsampleScript("yearly"), "0 2 1 1 *", orgID) if err != nil { return err } @@ -235,7 +269,7 @@ func (sr *scrutinyRepository) DownsampleScript(aggregationType string) string { smart_data = from(bucket: sourceBucket) |> range(start: rangeStart, stop: rangeEnd) |> filter(fn: (r) => r["_measurement"] == "smart" ) - |> filter(fn: (r) => r["_field"] !~ /(raw_string|_measurement|device_protocol|device_wwn|attribute_id|name|status|when_failed)/) + |> filter(fn: (r) => r["_field"] !~ /(raw_string|_measurement|device_protocol|device_wwn|attribute_id|when_failed)/) |> last() |> yield(name: "last") diff --git a/webapp/backend/pkg/models/measurements/smart.go b/webapp/backend/pkg/models/measurements/smart.go index 315bd11..d0c3a39 100644 --- a/webapp/backend/pkg/models/measurements/smart.go +++ b/webapp/backend/pkg/models/measurements/smart.go @@ -140,7 +140,6 @@ func (sm *Smart) ProcessAtaSmartInfo(info collector.SmartInfo) { for _, collectorAttr := range info.AtaSmartAttributes.Table { attrModel := SmartAtaAttribute{ AttributeId: collectorAttr.ID, - Name: collectorAttr.Name, Value: collectorAttr.Value, Worst: collectorAttr.Worst, Threshold: collectorAttr.Thresh, @@ -151,7 +150,6 @@ func (sm *Smart) ProcessAtaSmartInfo(info collector.SmartInfo) { //now that we've parsed the data from the smartctl response, lets match it against our metadata rules and add additional Scrutiny specific data. if smartMetadata, ok := thresholds.AtaMetadata[collectorAttr.ID]; ok { - attrModel.Name = smartMetadata.DisplayName if smartMetadata.Transform != nil { attrModel.TransformedValue = smartMetadata.Transform(attrModel.Value, attrModel.RawValue, attrModel.RawString) } @@ -168,22 +166,22 @@ func (sm *Smart) ProcessAtaSmartInfo(info collector.SmartInfo) { func (sm *Smart) ProcessNvmeSmartInfo(info collector.SmartInfo) { sm.Attributes = map[string]SmartAttribute{ - "critical_warning": (&SmartNvmeAttribute{AttributeId: "critical_warning", Name: "Critical Warning", Value: info.NvmeSmartHealthInformationLog.CriticalWarning, Threshold: 0}).PopulateAttributeStatus(), - "temperature": (&SmartNvmeAttribute{AttributeId: "temperature", Name: "Temperature", Value: info.NvmeSmartHealthInformationLog.Temperature, Threshold: -1}).PopulateAttributeStatus(), - "available_spare": (&SmartNvmeAttribute{AttributeId: "available_spare", Name: "Available Spare", Value: info.NvmeSmartHealthInformationLog.AvailableSpare, Threshold: info.NvmeSmartHealthInformationLog.AvailableSpareThreshold}).PopulateAttributeStatus(), - "percentage_used": (&SmartNvmeAttribute{AttributeId: "percentage_used", Name: "Percentage Used", Value: info.NvmeSmartHealthInformationLog.PercentageUsed, Threshold: 100}).PopulateAttributeStatus(), - "data_units_read": (&SmartNvmeAttribute{AttributeId: "data_units_read", Name: "Data Units Read", Value: info.NvmeSmartHealthInformationLog.DataUnitsRead, Threshold: -1}).PopulateAttributeStatus(), - "data_units_written": (&SmartNvmeAttribute{AttributeId: "data_units_written", Name: "Data Units Written", Value: info.NvmeSmartHealthInformationLog.DataUnitsWritten, Threshold: -1}).PopulateAttributeStatus(), - "host_reads": (&SmartNvmeAttribute{AttributeId: "host_reads", Name: "Host Reads", Value: info.NvmeSmartHealthInformationLog.HostReads, Threshold: -1}).PopulateAttributeStatus(), - "host_writes": (&SmartNvmeAttribute{AttributeId: "host_writes", Name: "Host Writes", Value: info.NvmeSmartHealthInformationLog.HostWrites, Threshold: -1}).PopulateAttributeStatus(), - "controller_busy_time": (&SmartNvmeAttribute{AttributeId: "controller_busy_time", Name: "Controller Busy Time", Value: info.NvmeSmartHealthInformationLog.ControllerBusyTime, Threshold: -1}).PopulateAttributeStatus(), - "power_cycles": (&SmartNvmeAttribute{AttributeId: "power_cycles", Name: "Power Cycles", Value: info.NvmeSmartHealthInformationLog.PowerCycles, Threshold: -1}).PopulateAttributeStatus(), - "power_on_hours": (&SmartNvmeAttribute{AttributeId: "power_on_hours", Name: "Power on Hours", Value: info.NvmeSmartHealthInformationLog.PowerOnHours, Threshold: -1}).PopulateAttributeStatus(), - "unsafe_shutdowns": (&SmartNvmeAttribute{AttributeId: "unsafe_shutdowns", Name: "Unsafe Shutdowns", Value: info.NvmeSmartHealthInformationLog.UnsafeShutdowns, Threshold: -1}).PopulateAttributeStatus(), - "media_errors": (&SmartNvmeAttribute{AttributeId: "media_errors", Name: "Media Errors", Value: info.NvmeSmartHealthInformationLog.MediaErrors, Threshold: 0}).PopulateAttributeStatus(), - "num_err_log_entries": (&SmartNvmeAttribute{AttributeId: "num_err_log_entries", Name: "Numb Err Log Entries", Value: info.NvmeSmartHealthInformationLog.NumErrLogEntries, Threshold: 0}).PopulateAttributeStatus(), - "warning_temp_time": (&SmartNvmeAttribute{AttributeId: "warning_temp_time", Name: "Warning Temp Time", Value: info.NvmeSmartHealthInformationLog.WarningTempTime, Threshold: -1}).PopulateAttributeStatus(), - "critical_comp_time": (&SmartNvmeAttribute{AttributeId: "critical_comp_time", Name: "Critical CompTime", Value: info.NvmeSmartHealthInformationLog.CriticalCompTime, Threshold: -1}).PopulateAttributeStatus(), + "critical_warning": (&SmartNvmeAttribute{AttributeId: "critical_warning", Value: info.NvmeSmartHealthInformationLog.CriticalWarning, Threshold: 0}).PopulateAttributeStatus(), + "temperature": (&SmartNvmeAttribute{AttributeId: "temperature", Value: info.NvmeSmartHealthInformationLog.Temperature, Threshold: -1}).PopulateAttributeStatus(), + "available_spare": (&SmartNvmeAttribute{AttributeId: "available_spare", Value: info.NvmeSmartHealthInformationLog.AvailableSpare, Threshold: info.NvmeSmartHealthInformationLog.AvailableSpareThreshold}).PopulateAttributeStatus(), + "percentage_used": (&SmartNvmeAttribute{AttributeId: "percentage_used", Value: info.NvmeSmartHealthInformationLog.PercentageUsed, Threshold: 100}).PopulateAttributeStatus(), + "data_units_read": (&SmartNvmeAttribute{AttributeId: "data_units_read", Value: info.NvmeSmartHealthInformationLog.DataUnitsRead, Threshold: -1}).PopulateAttributeStatus(), + "data_units_written": (&SmartNvmeAttribute{AttributeId: "data_units_written", Value: info.NvmeSmartHealthInformationLog.DataUnitsWritten, Threshold: -1}).PopulateAttributeStatus(), + "host_reads": (&SmartNvmeAttribute{AttributeId: "host_reads", Value: info.NvmeSmartHealthInformationLog.HostReads, Threshold: -1}).PopulateAttributeStatus(), + "host_writes": (&SmartNvmeAttribute{AttributeId: "host_writes", Value: info.NvmeSmartHealthInformationLog.HostWrites, Threshold: -1}).PopulateAttributeStatus(), + "controller_busy_time": (&SmartNvmeAttribute{AttributeId: "controller_busy_time", Value: info.NvmeSmartHealthInformationLog.ControllerBusyTime, Threshold: -1}).PopulateAttributeStatus(), + "power_cycles": (&SmartNvmeAttribute{AttributeId: "power_cycles", Value: info.NvmeSmartHealthInformationLog.PowerCycles, Threshold: -1}).PopulateAttributeStatus(), + "power_on_hours": (&SmartNvmeAttribute{AttributeId: "power_on_hours", Value: info.NvmeSmartHealthInformationLog.PowerOnHours, Threshold: -1}).PopulateAttributeStatus(), + "unsafe_shutdowns": (&SmartNvmeAttribute{AttributeId: "unsafe_shutdowns", Value: info.NvmeSmartHealthInformationLog.UnsafeShutdowns, Threshold: -1}).PopulateAttributeStatus(), + "media_errors": (&SmartNvmeAttribute{AttributeId: "media_errors", Value: info.NvmeSmartHealthInformationLog.MediaErrors, Threshold: 0}).PopulateAttributeStatus(), + "num_err_log_entries": (&SmartNvmeAttribute{AttributeId: "num_err_log_entries", Value: info.NvmeSmartHealthInformationLog.NumErrLogEntries, Threshold: 0}).PopulateAttributeStatus(), + "warning_temp_time": (&SmartNvmeAttribute{AttributeId: "warning_temp_time", Value: info.NvmeSmartHealthInformationLog.WarningTempTime, Threshold: -1}).PopulateAttributeStatus(), + "critical_comp_time": (&SmartNvmeAttribute{AttributeId: "critical_comp_time", Value: info.NvmeSmartHealthInformationLog.CriticalCompTime, Threshold: -1}).PopulateAttributeStatus(), } //find analyzed attribute status @@ -197,19 +195,19 @@ func (sm *Smart) ProcessNvmeSmartInfo(info collector.SmartInfo) { //generate SmartScsiAttribute entries from Scrutiny Collector Smart data. func (sm *Smart) ProcessScsiSmartInfo(info collector.SmartInfo) { sm.Attributes = map[string]SmartAttribute{ - "scsi_grown_defect_list": (&SmartScsiAttribute{AttributeId: "scsi_grown_defect_list", Name: "Grown Defect List", Value: info.ScsiGrownDefectList, Threshold: 0}).PopulateAttributeStatus(), - "read_errors_corrected_by_eccfast": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccfast", Name: "Read Errors Corrected by ECC Fast", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccfast, Threshold: -1}).PopulateAttributeStatus(), - "read_errors_corrected_by_eccdelayed": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccdelayed", Name: "Read Errors Corrected by ECC Delayed", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccdelayed, Threshold: -1}).PopulateAttributeStatus(), - "read_errors_corrected_by_rereads_rewrites": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_rereads_rewrites", Name: "Read Errors Corrected by ReReads/ReWrites", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByRereadsRewrites, Threshold: 0}).PopulateAttributeStatus(), - "read_total_errors_corrected": (&SmartScsiAttribute{AttributeId: "read_total_errors_corrected", Name: "Read Total Errors Corrected", Value: info.ScsiErrorCounterLog.Read.TotalErrorsCorrected, Threshold: -1}).PopulateAttributeStatus(), - "read_correction_algorithm_invocations": (&SmartScsiAttribute{AttributeId: "read_correction_algorithm_invocations", Name: "Read Correction Algorithm Invocations", Value: info.ScsiErrorCounterLog.Read.CorrectionAlgorithmInvocations, Threshold: -1}).PopulateAttributeStatus(), - "read_total_uncorrected_errors": (&SmartScsiAttribute{AttributeId: "read_total_uncorrected_errors", Name: "Read Total Uncorrected Errors", Value: info.ScsiErrorCounterLog.Read.TotalUncorrectedErrors, Threshold: 0}).PopulateAttributeStatus(), - "write_errors_corrected_by_eccfast": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccfast", Name: "Write Errors Corrected by ECC Fast", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccfast, Threshold: -1}).PopulateAttributeStatus(), - "write_errors_corrected_by_eccdelayed": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccdelayed", Name: "Write Errors Corrected by ECC Delayed", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccdelayed, Threshold: -1}).PopulateAttributeStatus(), - "write_errors_corrected_by_rereads_rewrites": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_rereads_rewrites", Name: "Write Errors Corrected by ReReads/ReWrites", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByRereadsRewrites, Threshold: 0}).PopulateAttributeStatus(), - "write_total_errors_corrected": (&SmartScsiAttribute{AttributeId: "write_total_errors_corrected", Name: "Write Total Errors Corrected", Value: info.ScsiErrorCounterLog.Write.TotalErrorsCorrected, Threshold: -1}).PopulateAttributeStatus(), - "write_correction_algorithm_invocations": (&SmartScsiAttribute{AttributeId: "write_correction_algorithm_invocations", Name: "Write Correction Algorithm Invocations", Value: info.ScsiErrorCounterLog.Write.CorrectionAlgorithmInvocations, Threshold: -1}).PopulateAttributeStatus(), - "write_total_uncorrected_errors": (&SmartScsiAttribute{AttributeId: "write_total_uncorrected_errors", Name: "Write Total Uncorrected Errors", Value: info.ScsiErrorCounterLog.Write.TotalUncorrectedErrors, Threshold: 0}).PopulateAttributeStatus(), + "scsi_grown_defect_list": (&SmartScsiAttribute{AttributeId: "scsi_grown_defect_list", Value: info.ScsiGrownDefectList, Threshold: 0}).PopulateAttributeStatus(), + "read_errors_corrected_by_eccfast": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccfast", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccfast, Threshold: -1}).PopulateAttributeStatus(), + "read_errors_corrected_by_eccdelayed": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccdelayed", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccdelayed, Threshold: -1}).PopulateAttributeStatus(), + "read_errors_corrected_by_rereads_rewrites": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_rereads_rewrites", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByRereadsRewrites, Threshold: 0}).PopulateAttributeStatus(), + "read_total_errors_corrected": (&SmartScsiAttribute{AttributeId: "read_total_errors_corrected", Value: info.ScsiErrorCounterLog.Read.TotalErrorsCorrected, Threshold: -1}).PopulateAttributeStatus(), + "read_correction_algorithm_invocations": (&SmartScsiAttribute{AttributeId: "read_correction_algorithm_invocations", Value: info.ScsiErrorCounterLog.Read.CorrectionAlgorithmInvocations, Threshold: -1}).PopulateAttributeStatus(), + "read_total_uncorrected_errors": (&SmartScsiAttribute{AttributeId: "read_total_uncorrected_errors", Value: info.ScsiErrorCounterLog.Read.TotalUncorrectedErrors, Threshold: 0}).PopulateAttributeStatus(), + "write_errors_corrected_by_eccfast": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccfast", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccfast, Threshold: -1}).PopulateAttributeStatus(), + "write_errors_corrected_by_eccdelayed": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccdelayed", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccdelayed, Threshold: -1}).PopulateAttributeStatus(), + "write_errors_corrected_by_rereads_rewrites": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_rereads_rewrites", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByRereadsRewrites, Threshold: 0}).PopulateAttributeStatus(), + "write_total_errors_corrected": (&SmartScsiAttribute{AttributeId: "write_total_errors_corrected", Value: info.ScsiErrorCounterLog.Write.TotalErrorsCorrected, Threshold: -1}).PopulateAttributeStatus(), + "write_correction_algorithm_invocations": (&SmartScsiAttribute{AttributeId: "write_correction_algorithm_invocations", Value: info.ScsiErrorCounterLog.Write.CorrectionAlgorithmInvocations, Threshold: -1}).PopulateAttributeStatus(), + "write_total_uncorrected_errors": (&SmartScsiAttribute{AttributeId: "write_total_uncorrected_errors", Value: info.ScsiErrorCounterLog.Write.TotalUncorrectedErrors, Threshold: 0}).PopulateAttributeStatus(), } //find analyzed attribute status diff --git a/webapp/backend/pkg/models/measurements/smart_ata_attribute.go b/webapp/backend/pkg/models/measurements/smart_ata_attribute.go index 230c124..23f95fb 100644 --- a/webapp/backend/pkg/models/measurements/smart_ata_attribute.go +++ b/webapp/backend/pkg/models/measurements/smart_ata_attribute.go @@ -10,7 +10,6 @@ import ( type SmartAtaAttribute struct { AttributeId int `json:"attribute_id"` - Name string `json:"name"` Value int64 `json:"value"` Threshold int64 `json:"thresh"` Worst int64 `json:"worst"` @@ -20,12 +19,12 @@ type SmartAtaAttribute struct { //Generated data TransformedValue int64 `json:"transformed_value"` - Status string `json:"status,omitempty"` + Status int64 `json:"status,omitempty"` StatusReason string `json:"status_reason,omitempty"` FailureRate float64 `json:"failure_rate,omitempty"` } -func (sa *SmartAtaAttribute) GetStatus() string { +func (sa *SmartAtaAttribute) GetStatus() int64 { return sa.Status } @@ -35,7 +34,6 @@ func (sa *SmartAtaAttribute) Flatten() map[string]interface{} { return map[string]interface{}{ fmt.Sprintf("attr.%s.attribute_id", idString): idString, - fmt.Sprintf("attr.%s.name", idString): sa.Name, fmt.Sprintf("attr.%s.value", idString): sa.Value, fmt.Sprintf("attr.%s.worst", idString): sa.Worst, fmt.Sprintf("attr.%s.thresh", idString): sa.Threshold, @@ -62,8 +60,6 @@ func (sa *SmartAtaAttribute) Inflate(key string, val interface{}) { if err == nil { sa.AttributeId = attrId } - case "name": - sa.Name = val.(string) case "value": sa.Value = val.(int64) case "worst": @@ -81,7 +77,7 @@ func (sa *SmartAtaAttribute) Inflate(key string, val interface{}) { case "transformed_value": sa.TransformedValue = val.(int64) case "status": - sa.Status = val.(string) + sa.Status = val.(int64) case "status_reason": sa.StatusReason = val.(string) case "failure_rate": @@ -107,10 +103,6 @@ func (sa *SmartAtaAttribute) PopulateAttributeStatus() *SmartAtaAttribute { sa.ValidateThreshold(smartMetadata) } - //check if status is blank, set to "passed" - if len(sa.Status) == 0 { - sa.Status = pkg.SmartAttributeStatusPassed - } return sa } diff --git a/webapp/backend/pkg/models/measurements/smart_attribute.go b/webapp/backend/pkg/models/measurements/smart_attribute.go index a8aaea6..02a4fa7 100644 --- a/webapp/backend/pkg/models/measurements/smart_attribute.go +++ b/webapp/backend/pkg/models/measurements/smart_attribute.go @@ -3,5 +3,5 @@ package measurements type SmartAttribute interface { Flatten() (fields map[string]interface{}) Inflate(key string, val interface{}) - GetStatus() string + GetStatus() int64 } diff --git a/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go b/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go index 0320824..3996945 100644 --- a/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go +++ b/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go @@ -9,24 +9,22 @@ import ( type SmartNvmeAttribute struct { AttributeId string `json:"attribute_id"` //json string from smartctl - Name string `json:"name"` Value int64 `json:"value"` Threshold int64 `json:"thresh"` TransformedValue int64 `json:"transformed_value"` - Status string `json:"status,omitempty"` + Status int64 `json:"status,omitempty"` StatusReason string `json:"status_reason,omitempty"` FailureRate float64 `json:"failure_rate,omitempty"` } -func (sa *SmartNvmeAttribute) GetStatus() string { +func (sa *SmartNvmeAttribute) GetStatus() int64 { return sa.Status } func (sa *SmartNvmeAttribute) Flatten() map[string]interface{} { return map[string]interface{}{ fmt.Sprintf("attr.%s.attribute_id", sa.AttributeId): sa.AttributeId, - fmt.Sprintf("attr.%s.name", sa.AttributeId): sa.Name, fmt.Sprintf("attr.%s.value", sa.AttributeId): sa.Value, fmt.Sprintf("attr.%s.thresh", sa.AttributeId): sa.Threshold, @@ -47,8 +45,6 @@ func (sa *SmartNvmeAttribute) Inflate(key string, val interface{}) { switch keyParts[2] { case "attribute_id": sa.AttributeId = val.(string) - case "name": - sa.Name = val.(string) case "value": sa.Value = val.(int64) case "thresh": @@ -58,7 +54,7 @@ func (sa *SmartNvmeAttribute) Inflate(key string, val interface{}) { case "transformed_value": sa.TransformedValue = val.(int64) case "status": - sa.Status = val.(string) + sa.Status = val.(int64) case "status_reason": sa.StatusReason = val.(string) case "failure_rate": @@ -83,9 +79,5 @@ func (sa *SmartNvmeAttribute) PopulateAttributeStatus() *SmartNvmeAttribute { } //TODO: eventually figure out the critical_warning bits and determine correct error messages here. - //check if status is blank, set to "passed" - if len(sa.Status) == 0 { - sa.Status = pkg.SmartAttributeStatusPassed - } return sa } diff --git a/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go b/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go index a2f1ea1..d21229d 100644 --- a/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go +++ b/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go @@ -9,24 +9,22 @@ import ( type SmartScsiAttribute struct { AttributeId string `json:"attribute_id"` //json string from smartctl - Name string `json:"name"` Value int64 `json:"value"` Threshold int64 `json:"thresh"` TransformedValue int64 `json:"transformed_value"` - Status string `json:"status,omitempty"` + Status int64 `json:"status,omitempty"` StatusReason string `json:"status_reason,omitempty"` FailureRate float64 `json:"failure_rate,omitempty"` } -func (sa *SmartScsiAttribute) GetStatus() string { +func (sa *SmartScsiAttribute) GetStatus() int64 { return sa.Status } func (sa *SmartScsiAttribute) Flatten() map[string]interface{} { return map[string]interface{}{ fmt.Sprintf("attr.%s.attribute_id", sa.AttributeId): sa.AttributeId, - fmt.Sprintf("attr.%s.name", sa.AttributeId): sa.Name, fmt.Sprintf("attr.%s.value", sa.AttributeId): sa.Value, fmt.Sprintf("attr.%s.thresh", sa.AttributeId): sa.Threshold, @@ -47,8 +45,6 @@ func (sa *SmartScsiAttribute) Inflate(key string, val interface{}) { switch keyParts[2] { case "attribute_id": sa.AttributeId = val.(string) - case "name": - sa.Name = val.(string) case "value": sa.Value = val.(int64) case "thresh": @@ -58,7 +54,7 @@ func (sa *SmartScsiAttribute) Inflate(key string, val interface{}) { case "transformed_value": sa.TransformedValue = val.(int64) case "status": - sa.Status = val.(string) + sa.Status = val.(int64) case "status_reason": sa.StatusReason = val.(string) case "failure_rate": @@ -83,9 +79,5 @@ func (sa *SmartScsiAttribute) PopulateAttributeStatus() *SmartScsiAttribute { } } - //check if status is blank, set to "passed" - if len(sa.Status) == 0 { - sa.Status = pkg.SmartAttributeStatusPassed - } return sa } diff --git a/webapp/backend/pkg/thresholds/ata_attribute_metadata.go b/webapp/backend/pkg/thresholds/ata_attribute_metadata.go index 0628a18..3bd98eb 100644 --- a/webapp/backend/pkg/thresholds/ata_attribute_metadata.go +++ b/webapp/backend/pkg/thresholds/ata_attribute_metadata.go @@ -6,7 +6,7 @@ const AtaSmartAttributeDisplayTypeTransformed = "transformed" type AtaAttributeMetadata struct { ID int64 `json:"-"` - DisplayName string `json:"-"` + DisplayName string `json:"display_name"` Ideal string `json:"ideal"` Critical bool `json:"critical"` Description string `json:"description"` From deba21fe19513bef5e27726cfc535626b520809e Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 24 Oct 2021 16:26:41 -0700 Subject: [PATCH 031/114] update timestamps for testing. --- CONTRIBUTING.md | 3 +++ webapp/backend/pkg/models/testdata/smart-ata-date.json | 2 +- webapp/backend/pkg/models/testdata/smart-ata-date2.json | 2 +- webapp/backend/pkg/models/testdata/smart-ata-full.json | 2 +- webapp/backend/pkg/models/testdata/smart-ata.json | 2 +- webapp/backend/pkg/models/testdata/smart-ata2.json | 2 +- webapp/backend/pkg/models/testdata/smart-fail2.json | 2 +- webapp/backend/pkg/models/testdata/smart-megaraid0.json | 2 +- webapp/backend/pkg/models/testdata/smart-megaraid1.json | 2 +- webapp/backend/pkg/models/testdata/smart-nvme.json | 2 +- webapp/backend/pkg/models/testdata/smart-nvme2.json | 2 +- webapp/backend/pkg/models/testdata/smart-raid.json | 2 +- webapp/backend/pkg/models/testdata/smart-scsi.json | 2 +- webapp/backend/pkg/models/testdata/smart-scsi2.json | 2 +- 14 files changed, 16 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8e4f34b..48f0cb6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -73,6 +73,9 @@ Now visit http://localhost:8080 If you'd like to populate the database with some test data, you can run the following commands: +> NOTE: you may need to update the `local_time` key within the JSON file, any timestamps older than ~3 weeks will be automatically ignored +> (since the downsampling & retention policy takes effect at 2 weeks) + ``` docker run -p 8086:8086 --rm influxdb:2.0 diff --git a/webapp/backend/pkg/models/testdata/smart-ata-date.json b/webapp/backend/pkg/models/testdata/smart-ata-date.json index f654a3a..b4a531d 100644 --- a/webapp/backend/pkg/models/testdata/smart-ata-date.json +++ b/webapp/backend/pkg/models/testdata/smart-ata-date.json @@ -69,7 +69,7 @@ } }, "local_time": { - "time_t": 1611419146, + "time_t": 1635117644, "asctime": "Sun Jun 30 00:03:30 2021 UTC" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-ata-date2.json b/webapp/backend/pkg/models/testdata/smart-ata-date2.json index 78ca0f9..efbdec3 100644 --- a/webapp/backend/pkg/models/testdata/smart-ata-date2.json +++ b/webapp/backend/pkg/models/testdata/smart-ata-date2.json @@ -69,7 +69,7 @@ } }, "local_time": { - "time_t": 1614101651, + "time_t": 1635117644, "asctime": "Tue Feb 23 00:03:30 2021 UTC" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-ata-full.json b/webapp/backend/pkg/models/testdata/smart-ata-full.json index 82b5250..bf7a3d5 100644 --- a/webapp/backend/pkg/models/testdata/smart-ata-full.json +++ b/webapp/backend/pkg/models/testdata/smart-ata-full.json @@ -70,7 +70,7 @@ } }, "local_time": { - "time_t": 1600014563, + "time_t": 1635117644, "asctime": "Sun Sep 13 16:29:23 2020 UTC" }, "read_lookahead": { diff --git a/webapp/backend/pkg/models/testdata/smart-ata.json b/webapp/backend/pkg/models/testdata/smart-ata.json index 36ac36b..421fed6 100644 --- a/webapp/backend/pkg/models/testdata/smart-ata.json +++ b/webapp/backend/pkg/models/testdata/smart-ata.json @@ -69,7 +69,7 @@ } }, "local_time": { - "time_t": 1592697810, + "time_t": 1635117644, "asctime": "Sun Jun 21 00:03:30 2020 UTC" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-ata2.json b/webapp/backend/pkg/models/testdata/smart-ata2.json index b981b10..4480c55 100644 --- a/webapp/backend/pkg/models/testdata/smart-ata2.json +++ b/webapp/backend/pkg/models/testdata/smart-ata2.json @@ -66,7 +66,7 @@ } }, "local_time": { - "time_t": 1564664713, + "time_t": 1635117644, "asctime": "Thu Aug 01 15:05:13 2019 WEDT" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-fail2.json b/webapp/backend/pkg/models/testdata/smart-fail2.json index 4fbfb88..e7571e6 100644 --- a/webapp/backend/pkg/models/testdata/smart-fail2.json +++ b/webapp/backend/pkg/models/testdata/smart-fail2.json @@ -70,7 +70,7 @@ } }, "local_time": { - "time_t": 1594216103, + "time_t": 1635117644, "asctime": "Wed Jul 8 15:48:23 2020 CEST" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-megaraid0.json b/webapp/backend/pkg/models/testdata/smart-megaraid0.json index 5767206..9f51c62 100644 --- a/webapp/backend/pkg/models/testdata/smart-megaraid0.json +++ b/webapp/backend/pkg/models/testdata/smart-megaraid0.json @@ -79,7 +79,7 @@ } }, "local_time": { - "time_t": 1598297918, + "time_t": 1635117644, "asctime": "Mon Aug 24 21:38:38 2020 CEST" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-megaraid1.json b/webapp/backend/pkg/models/testdata/smart-megaraid1.json index 04a2af2..4a0043a 100644 --- a/webapp/backend/pkg/models/testdata/smart-megaraid1.json +++ b/webapp/backend/pkg/models/testdata/smart-megaraid1.json @@ -79,7 +79,7 @@ } }, "local_time": { - "time_t": 1598297922, + "time_t": 1635117644, "asctime": "Mon Aug 24 21:38:42 2020 CEST" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-nvme.json b/webapp/backend/pkg/models/testdata/smart-nvme.json index c6b6ec8..232e88f 100644 --- a/webapp/backend/pkg/models/testdata/smart-nvme.json +++ b/webapp/backend/pkg/models/testdata/smart-nvme.json @@ -59,7 +59,7 @@ }, "logical_block_size": 512, "local_time": { - "time_t": 1591790462, + "time_t": 1635117644, "asctime": "Wed Jun 10 14:01:02 2020 CEST" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-nvme2.json b/webapp/backend/pkg/models/testdata/smart-nvme2.json index 4f47c1a..5d03273 100644 --- a/webapp/backend/pkg/models/testdata/smart-nvme2.json +++ b/webapp/backend/pkg/models/testdata/smart-nvme2.json @@ -67,7 +67,7 @@ }, "logical_block_size": 512, "local_time": { - "time_t": 1600619090, + "time_t": 1635117644, "asctime": "Sun Sep 20 16:24:50 2020 Europe" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-raid.json b/webapp/backend/pkg/models/testdata/smart-raid.json index 951548d..364285c 100644 --- a/webapp/backend/pkg/models/testdata/smart-raid.json +++ b/webapp/backend/pkg/models/testdata/smart-raid.json @@ -43,7 +43,7 @@ "name": "disk" }, "local_time": { - "time_t": 1570609867, + "time_t": 1635117644, "asctime": "Wed Oct 09 10:31:07 2019 RDT" }, "temperature": { diff --git a/webapp/backend/pkg/models/testdata/smart-scsi.json b/webapp/backend/pkg/models/testdata/smart-scsi.json index fe0cfb7..0b12720 100644 --- a/webapp/backend/pkg/models/testdata/smart-scsi.json +++ b/webapp/backend/pkg/models/testdata/smart-scsi.json @@ -26,7 +26,7 @@ "name": "disk" }, "local_time": { - "time_t": 1598048822, + "time_t": 1635117644, "asctime": "Fri Aug 21 22:27:02 2020 UTC" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-scsi2.json b/webapp/backend/pkg/models/testdata/smart-scsi2.json index 26f9470..0995356 100644 --- a/webapp/backend/pkg/models/testdata/smart-scsi2.json +++ b/webapp/backend/pkg/models/testdata/smart-scsi2.json @@ -44,7 +44,7 @@ "name": "disk" }, "local_time": { - "time_t": 1545001755, + "time_t": 1635117644, "asctime": "Sun Dec 16 17:09:15 2018 CST" }, "smart_status": { From 5789c836db742a7cde0865cf6fdcea8d0d187aaa Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 24 Oct 2021 17:09:44 -0700 Subject: [PATCH 032/114] make sure the status is always exposed in the json data. make sure display_name for metadata is included. Update mocked test data for frontend. --- .../measurements/smart_ata_attribute.go | 2 +- .../measurements/smart_nvme_attribute.go | 2 +- .../measurements/smart_scsci_attribute.go | 2 +- .../pkg/models/testdata/smart-ata-date.json | 2 +- .../pkg/models/testdata/smart-ata-date2.json | 2 +- .../pkg/thresholds/nvme_attribute_metadata.go | 2 +- .../pkg/thresholds/scsi_attribute_metadata.go | 2 +- webapp/frontend/package-lock.json | 888 +++----- .../src/app/data/mock/device/details/sda.ts | 87 +- .../src/app/data/mock/device/details/sdb.ts | 470 ++-- .../src/app/data/mock/device/details/sdc.ts | 367 ++- .../src/app/data/mock/device/details/sdd.ts | 172 +- .../src/app/data/mock/device/details/sde.ts | 1374 ++---------- .../src/app/data/mock/device/details/sdf.ts | 1998 +---------------- .../app/modules/detail/detail.component.html | 16 +- .../app/modules/detail/detail.component.ts | 20 + 16 files changed, 960 insertions(+), 4446 deletions(-) diff --git a/webapp/backend/pkg/models/measurements/smart_ata_attribute.go b/webapp/backend/pkg/models/measurements/smart_ata_attribute.go index 23f95fb..7b0606c 100644 --- a/webapp/backend/pkg/models/measurements/smart_ata_attribute.go +++ b/webapp/backend/pkg/models/measurements/smart_ata_attribute.go @@ -19,7 +19,7 @@ type SmartAtaAttribute struct { //Generated data TransformedValue int64 `json:"transformed_value"` - Status int64 `json:"status,omitempty"` + Status int64 `json:"status"` StatusReason string `json:"status_reason,omitempty"` FailureRate float64 `json:"failure_rate,omitempty"` } diff --git a/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go b/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go index 3996945..c4fbe0e 100644 --- a/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go +++ b/webapp/backend/pkg/models/measurements/smart_nvme_attribute.go @@ -13,7 +13,7 @@ type SmartNvmeAttribute struct { Threshold int64 `json:"thresh"` TransformedValue int64 `json:"transformed_value"` - Status int64 `json:"status,omitempty"` + Status int64 `json:"status"` StatusReason string `json:"status_reason,omitempty"` FailureRate float64 `json:"failure_rate,omitempty"` } diff --git a/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go b/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go index d21229d..f9049a6 100644 --- a/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go +++ b/webapp/backend/pkg/models/measurements/smart_scsci_attribute.go @@ -13,7 +13,7 @@ type SmartScsiAttribute struct { Threshold int64 `json:"thresh"` TransformedValue int64 `json:"transformed_value"` - Status int64 `json:"status,omitempty"` + Status int64 `json:"status"` StatusReason string `json:"status_reason,omitempty"` FailureRate float64 `json:"failure_rate,omitempty"` } diff --git a/webapp/backend/pkg/models/testdata/smart-ata-date.json b/webapp/backend/pkg/models/testdata/smart-ata-date.json index b4a531d..92c9382 100644 --- a/webapp/backend/pkg/models/testdata/smart-ata-date.json +++ b/webapp/backend/pkg/models/testdata/smart-ata-date.json @@ -69,7 +69,7 @@ } }, "local_time": { - "time_t": 1635117644, + "time_t": 1635107644, "asctime": "Sun Jun 30 00:03:30 2021 UTC" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-ata-date2.json b/webapp/backend/pkg/models/testdata/smart-ata-date2.json index efbdec3..3cced16 100644 --- a/webapp/backend/pkg/models/testdata/smart-ata-date2.json +++ b/webapp/backend/pkg/models/testdata/smart-ata-date2.json @@ -69,7 +69,7 @@ } }, "local_time": { - "time_t": 1635117644, + "time_t": 1635127644, "asctime": "Tue Feb 23 00:03:30 2021 UTC" }, "smart_status": { diff --git a/webapp/backend/pkg/thresholds/nvme_attribute_metadata.go b/webapp/backend/pkg/thresholds/nvme_attribute_metadata.go index 8ac4c8d..ad79988 100644 --- a/webapp/backend/pkg/thresholds/nvme_attribute_metadata.go +++ b/webapp/backend/pkg/thresholds/nvme_attribute_metadata.go @@ -6,7 +6,7 @@ package thresholds // https://www.micromat.com/product_manuals/drive_scope_manual_01.pdf type NvmeAttributeMetadata struct { ID string `json:"-"` - DisplayName string `json:"-"` + DisplayName string `json:"display_name"` Ideal string `json:"ideal"` Critical bool `json:"critical"` Description string `json:"description"` diff --git a/webapp/backend/pkg/thresholds/scsi_attribute_metadata.go b/webapp/backend/pkg/thresholds/scsi_attribute_metadata.go index 51cbbaa..83437fc 100644 --- a/webapp/backend/pkg/thresholds/scsi_attribute_metadata.go +++ b/webapp/backend/pkg/thresholds/scsi_attribute_metadata.go @@ -2,7 +2,7 @@ package thresholds type ScsiAttributeMetadata struct { ID string `json:"-"` - DisplayName string `json:"-"` + DisplayName string `json:"display_name"` Ideal string `json:"ideal"` Critical bool `json:"critical"` Description string `json:"description"` diff --git a/webapp/frontend/package-lock.json b/webapp/frontend/package-lock.json index cae08a9..1e3751f 100644 --- a/webapp/frontend/package-lock.json +++ b/webapp/frontend/package-lock.json @@ -15984,34 +15984,30 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/abbrev": { "version": "1.1.1", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/watchpack/node_modules/fsevents/node_modules/ansi-regex": { "version": "2.1.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/aproba": { "version": "1.2.0", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/watchpack/node_modules/fsevents/node_modules/are-we-there-yet": { "version": "1.1.5", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -16019,17 +16015,15 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/balanced-match": { "version": "1.0.0", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/watchpack/node_modules/fsevents/node_modules/brace-expansion": { "version": "1.1.11", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -16037,75 +16031,66 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/chownr": { "version": "1.1.4", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/watchpack/node_modules/fsevents/node_modules/code-point-at": { "version": "1.1.0", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/concat-map": { "version": "0.0.1", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/watchpack/node_modules/fsevents/node_modules/console-control-strings": { "version": "1.1.0", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/watchpack/node_modules/fsevents/node_modules/core-util-is": { "version": "1.0.2", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/watchpack/node_modules/fsevents/node_modules/debug": { "version": "3.2.6", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "ms": "^2.1.1" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/deep-extend": { "version": "0.6.0", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=4.0.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/delegates": { "version": "1.0.0", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/watchpack/node_modules/fsevents/node_modules/detect-libc": { "version": "1.0.3", - "dev": true, + "extraneous": true, "inBundle": true, "license": "Apache-2.0", - "optional": true, "bin": { "detect-libc": "bin/detect-libc.js" }, @@ -16115,27 +16100,24 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/fs-minipass": { "version": "1.2.7", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "minipass": "^2.6.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/fs.realpath": { "version": "1.0.0", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/watchpack/node_modules/fsevents/node_modules/gauge": { "version": "2.7.4", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -16149,10 +16131,9 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/glob": { "version": "7.1.6", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -16170,17 +16151,15 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/has-unicode": { "version": "2.0.1", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/watchpack/node_modules/fsevents/node_modules/iconv-lite": { "version": "0.4.24", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -16190,20 +16169,18 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/ignore-walk": { "version": "3.0.3", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "minimatch": "^3.0.4" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/inflight": { "version": "1.0.6", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -16211,27 +16188,24 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/inherits": { "version": "2.0.4", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/watchpack/node_modules/fsevents/node_modules/ini": { "version": "1.3.5", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "engines": { "node": "*" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/is-fullwidth-code-point": { "version": "1.0.0", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "number-is-nan": "^1.0.0" }, @@ -16241,17 +16215,15 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/isarray": { "version": "1.0.0", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/watchpack/node_modules/fsevents/node_modules/minimatch": { "version": "3.0.4", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -16261,17 +16233,15 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/minimist": { "version": "1.2.5", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/watchpack/node_modules/fsevents/node_modules/minipass": { "version": "2.9.0", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -16279,10 +16249,9 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/minizlib": { "version": "1.3.3", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "minipass": "^2.9.0" } @@ -16290,10 +16259,9 @@ "node_modules/watchpack/node_modules/fsevents/node_modules/mkdirp": { "version": "0.5.3", "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "minimist": "^1.2.5" }, @@ -16303,17 +16271,15 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/ms": { "version": "2.1.2", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/watchpack/node_modules/fsevents/node_modules/needle": { "version": "2.3.3", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "debug": "^3.2.6", "iconv-lite": "^0.4.4", @@ -16328,10 +16294,9 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/node-pre-gyp": { "version": "0.14.0", - "dev": true, + "extraneous": true, "inBundle": true, "license": "BSD-3-Clause", - "optional": true, "dependencies": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", @@ -16350,10 +16315,9 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/nopt": { "version": "4.0.3", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "abbrev": "1", "osenv": "^0.1.4" @@ -16364,27 +16328,24 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/npm-bundled": { "version": "1.1.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "npm-normalize-package-bin": "^1.0.1" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/npm-normalize-package-bin": { "version": "1.0.1", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/watchpack/node_modules/fsevents/node_modules/npm-packlist": { "version": "1.4.8", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1", @@ -16393,10 +16354,9 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/npmlog": { "version": "4.1.2", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -16406,60 +16366,54 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/number-is-nan": { "version": "1.0.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/object-assign": { "version": "4.1.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/once": { "version": "1.4.0", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "wrappy": "1" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/os-homedir": { "version": "1.0.2", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/os-tmpdir": { "version": "1.0.2", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/osenv": { "version": "0.1.5", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -16467,27 +16421,24 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/path-is-absolute": { "version": "1.0.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/process-nextick-args": { "version": "2.0.1", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/watchpack/node_modules/fsevents/node_modules/rc": { "version": "1.2.8", - "dev": true, + "extraneous": true, "inBundle": true, "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "optional": true, "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -16500,10 +16451,9 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/readable-stream": { "version": "2.3.7", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -16516,10 +16466,9 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/rimraf": { "version": "2.7.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "glob": "^7.1.3" }, @@ -16529,65 +16478,57 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/safe-buffer": { "version": "5.1.2", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/watchpack/node_modules/fsevents/node_modules/safer-buffer": { "version": "2.1.2", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/watchpack/node_modules/fsevents/node_modules/sax": { "version": "1.2.4", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/watchpack/node_modules/fsevents/node_modules/semver": { "version": "5.7.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "bin": { "semver": "bin/semver" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/set-blocking": { "version": "2.0.0", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/watchpack/node_modules/fsevents/node_modules/signal-exit": { "version": "3.0.2", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/watchpack/node_modules/fsevents/node_modules/string_decoder": { "version": "1.1.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "safe-buffer": "~5.1.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/string-width": { "version": "1.0.2", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -16599,10 +16540,9 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/strip-ansi": { "version": "3.0.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "ansi-regex": "^2.0.0" }, @@ -16612,20 +16552,18 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/strip-json-comments": { "version": "2.0.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/tar": { "version": "4.4.13", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", @@ -16641,34 +16579,30 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/util-deprecate": { "version": "1.0.2", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/watchpack/node_modules/fsevents/node_modules/wide-align": { "version": "1.1.3", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "string-width": "^1.0.2 || 2" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/wrappy": { "version": "1.0.2", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/watchpack/node_modules/fsevents/node_modules/yallist": { "version": "3.1.1", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/watchpack/node_modules/is-binary-path": { "version": "1.0.1", @@ -17033,34 +16967,30 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/abbrev": { "version": "1.1.1", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/ansi-regex": { "version": "2.1.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/aproba": { "version": "1.2.0", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/are-we-there-yet": { "version": "1.1.5", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -17068,17 +16998,15 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/balanced-match": { "version": "1.0.0", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/brace-expansion": { "version": "1.1.11", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -17086,75 +17014,66 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/chownr": { "version": "1.1.4", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/code-point-at": { "version": "1.1.0", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/concat-map": { "version": "0.0.1", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/console-control-strings": { "version": "1.1.0", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/core-util-is": { "version": "1.0.2", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/debug": { "version": "3.2.6", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "ms": "^2.1.1" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/deep-extend": { "version": "0.6.0", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=4.0.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/delegates": { "version": "1.0.0", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/detect-libc": { "version": "1.0.3", - "dev": true, + "extraneous": true, "inBundle": true, "license": "Apache-2.0", - "optional": true, "bin": { "detect-libc": "bin/detect-libc.js" }, @@ -17164,27 +17083,24 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/fs-minipass": { "version": "1.2.7", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "minipass": "^2.6.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/fs.realpath": { "version": "1.0.0", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/gauge": { "version": "2.7.4", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -17198,10 +17114,9 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/glob": { "version": "7.1.6", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -17219,17 +17134,15 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/has-unicode": { "version": "2.0.1", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/iconv-lite": { "version": "0.4.24", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -17239,20 +17152,18 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/ignore-walk": { "version": "3.0.3", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "minimatch": "^3.0.4" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/inflight": { "version": "1.0.6", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -17260,27 +17171,24 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/inherits": { "version": "2.0.4", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/ini": { "version": "1.3.5", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "engines": { "node": "*" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/is-fullwidth-code-point": { "version": "1.0.0", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "number-is-nan": "^1.0.0" }, @@ -17290,17 +17198,15 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/isarray": { "version": "1.0.0", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/minimatch": { "version": "3.0.4", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -17310,17 +17216,15 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/minimist": { "version": "1.2.5", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/minipass": { "version": "2.9.0", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -17328,10 +17232,9 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/minizlib": { "version": "1.3.3", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "minipass": "^2.9.0" } @@ -17339,10 +17242,9 @@ "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/mkdirp": { "version": "0.5.3", "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "minimist": "^1.2.5" }, @@ -17352,17 +17254,15 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/ms": { "version": "2.1.2", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/needle": { "version": "2.3.3", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "debug": "^3.2.6", "iconv-lite": "^0.4.4", @@ -17377,10 +17277,9 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/node-pre-gyp": { "version": "0.14.0", - "dev": true, + "extraneous": true, "inBundle": true, "license": "BSD-3-Clause", - "optional": true, "dependencies": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", @@ -17399,10 +17298,9 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/nopt": { "version": "4.0.3", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "abbrev": "1", "osenv": "^0.1.4" @@ -17413,27 +17311,24 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/npm-bundled": { "version": "1.1.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "npm-normalize-package-bin": "^1.0.1" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/npm-normalize-package-bin": { "version": "1.0.1", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/npm-packlist": { "version": "1.4.8", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1", @@ -17442,10 +17337,9 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/npmlog": { "version": "4.1.2", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -17455,60 +17349,54 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/number-is-nan": { "version": "1.0.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/object-assign": { "version": "4.1.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/once": { "version": "1.4.0", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "wrappy": "1" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/os-homedir": { "version": "1.0.2", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/os-tmpdir": { "version": "1.0.2", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/osenv": { "version": "0.1.5", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -17516,27 +17404,24 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/path-is-absolute": { "version": "1.0.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/process-nextick-args": { "version": "2.0.1", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/rc": { "version": "1.2.8", - "dev": true, + "extraneous": true, "inBundle": true, "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "optional": true, "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -17549,10 +17434,9 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/readable-stream": { "version": "2.3.7", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -17565,10 +17449,9 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/rimraf": { "version": "2.7.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "glob": "^7.1.3" }, @@ -17578,65 +17461,57 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/safe-buffer": { "version": "5.1.2", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/safer-buffer": { "version": "2.1.2", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/sax": { "version": "1.2.4", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/semver": { "version": "5.7.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "bin": { "semver": "bin/semver" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/set-blocking": { "version": "2.0.0", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/signal-exit": { "version": "3.0.2", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/string_decoder": { "version": "1.1.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "safe-buffer": "~5.1.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/string-width": { "version": "1.0.2", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -17648,10 +17523,9 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/strip-ansi": { "version": "3.0.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "ansi-regex": "^2.0.0" }, @@ -17661,20 +17535,18 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/strip-json-comments": { "version": "2.0.1", - "dev": true, + "extraneous": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/tar": { "version": "4.4.13", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", @@ -17690,34 +17562,30 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/util-deprecate": { "version": "1.0.2", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/wide-align": { "version": "1.1.3", - "dev": true, + "extraneous": true, "inBundle": true, "license": "ISC", - "optional": true, "dependencies": { "string-width": "^1.0.2 || 2" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/wrappy": { "version": "1.0.2", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/yallist": { "version": "3.1.1", - "dev": true, + "extraneous": true, "inBundle": true, - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/webpack-dev-server/node_modules/is-absolute-url": { "version": "3.0.3", @@ -31473,26 +31341,22 @@ "abbrev": { "version": "1.1.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "aproba": { "version": "1.2.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "are-we-there-yet": { "version": "1.1.5", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -31501,14 +31365,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -31517,38 +31379,32 @@ "chownr": { "version": "1.1.4", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "core-util-is": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "debug": { "version": "3.2.6", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "ms": "^2.1.1" } @@ -31556,26 +31412,22 @@ "deep-extend": { "version": "0.6.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "delegates": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "detect-libc": { "version": "1.0.3", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "fs-minipass": { "version": "1.2.7", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "minipass": "^2.6.0" } @@ -31583,14 +31435,12 @@ "fs.realpath": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "gauge": { "version": "2.7.4", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -31605,8 +31455,7 @@ "glob": { "version": "7.1.6", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -31619,14 +31468,12 @@ "has-unicode": { "version": "2.0.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "iconv-lite": { "version": "0.4.24", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -31634,8 +31481,7 @@ "ignore-walk": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "minimatch": "^3.0.4" } @@ -31643,8 +31489,7 @@ "inflight": { "version": "1.0.6", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -31653,20 +31498,17 @@ "inherits": { "version": "2.0.4", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "ini": { "version": "1.3.5", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "number-is-nan": "^1.0.0" } @@ -31674,14 +31516,12 @@ "isarray": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "minimatch": { "version": "3.0.4", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "brace-expansion": "^1.1.7" } @@ -31689,14 +31529,12 @@ "minimist": { "version": "1.2.5", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "minipass": { "version": "2.9.0", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -31705,8 +31543,7 @@ "minizlib": { "version": "1.3.3", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "minipass": "^2.9.0" } @@ -31714,8 +31551,7 @@ "mkdirp": { "version": "0.5.3", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "minimist": "^1.2.5" } @@ -31723,14 +31559,12 @@ "ms": { "version": "2.1.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "needle": { "version": "2.3.3", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "debug": "^3.2.6", "iconv-lite": "^0.4.4", @@ -31740,8 +31574,7 @@ "node-pre-gyp": { "version": "0.14.0", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", @@ -31758,8 +31591,7 @@ "nopt": { "version": "4.0.3", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "abbrev": "1", "osenv": "^0.1.4" @@ -31768,8 +31600,7 @@ "npm-bundled": { "version": "1.1.1", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "npm-normalize-package-bin": "^1.0.1" } @@ -31777,14 +31608,12 @@ "npm-normalize-package-bin": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "npm-packlist": { "version": "1.4.8", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1", @@ -31794,8 +31623,7 @@ "npmlog": { "version": "4.1.2", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -31806,20 +31634,17 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "object-assign": { "version": "4.1.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "once": { "version": "1.4.0", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "wrappy": "1" } @@ -31827,20 +31652,17 @@ "os-homedir": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "os-tmpdir": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "osenv": { "version": "0.1.5", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -31849,20 +31671,17 @@ "path-is-absolute": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "process-nextick-args": { "version": "2.0.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "rc": { "version": "1.2.8", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -31873,8 +31692,7 @@ "readable-stream": { "version": "2.3.7", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -31888,8 +31706,7 @@ "rimraf": { "version": "2.7.1", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "glob": "^7.1.3" } @@ -31897,44 +31714,37 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "safer-buffer": { "version": "2.1.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "sax": { "version": "1.2.4", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "semver": { "version": "5.7.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "set-blocking": { "version": "2.0.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "signal-exit": { "version": "3.0.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "string_decoder": { "version": "1.1.1", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "safe-buffer": "~5.1.0" } @@ -31942,8 +31752,7 @@ "string-width": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -31953,8 +31762,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "ansi-regex": "^2.0.0" } @@ -31962,14 +31770,12 @@ "strip-json-comments": { "version": "2.0.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "tar": { "version": "4.4.13", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", @@ -31983,14 +31789,12 @@ "util-deprecate": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "wide-align": { "version": "1.1.3", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "string-width": "^1.0.2 || 2" } @@ -31998,14 +31802,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "yallist": { "version": "3.1.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true } } }, @@ -32420,26 +32222,22 @@ "abbrev": { "version": "1.1.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "aproba": { "version": "1.2.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "are-we-there-yet": { "version": "1.1.5", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -32448,14 +32246,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -32464,38 +32260,32 @@ "chownr": { "version": "1.1.4", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "core-util-is": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "debug": { "version": "3.2.6", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "ms": "^2.1.1" } @@ -32503,26 +32293,22 @@ "deep-extend": { "version": "0.6.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "delegates": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "detect-libc": { "version": "1.0.3", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "fs-minipass": { "version": "1.2.7", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "minipass": "^2.6.0" } @@ -32530,14 +32316,12 @@ "fs.realpath": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "gauge": { "version": "2.7.4", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -32552,8 +32336,7 @@ "glob": { "version": "7.1.6", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -32566,14 +32349,12 @@ "has-unicode": { "version": "2.0.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "iconv-lite": { "version": "0.4.24", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -32581,8 +32362,7 @@ "ignore-walk": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "minimatch": "^3.0.4" } @@ -32590,8 +32370,7 @@ "inflight": { "version": "1.0.6", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -32600,20 +32379,17 @@ "inherits": { "version": "2.0.4", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "ini": { "version": "1.3.5", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "number-is-nan": "^1.0.0" } @@ -32621,14 +32397,12 @@ "isarray": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "minimatch": { "version": "3.0.4", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "brace-expansion": "^1.1.7" } @@ -32636,14 +32410,12 @@ "minimist": { "version": "1.2.5", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "minipass": { "version": "2.9.0", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -32652,8 +32424,7 @@ "minizlib": { "version": "1.3.3", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "minipass": "^2.9.0" } @@ -32661,8 +32432,7 @@ "mkdirp": { "version": "0.5.3", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "minimist": "^1.2.5" } @@ -32670,14 +32440,12 @@ "ms": { "version": "2.1.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "needle": { "version": "2.3.3", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "debug": "^3.2.6", "iconv-lite": "^0.4.4", @@ -32687,8 +32455,7 @@ "node-pre-gyp": { "version": "0.14.0", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", @@ -32705,8 +32472,7 @@ "nopt": { "version": "4.0.3", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "abbrev": "1", "osenv": "^0.1.4" @@ -32715,8 +32481,7 @@ "npm-bundled": { "version": "1.1.1", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "npm-normalize-package-bin": "^1.0.1" } @@ -32724,14 +32489,12 @@ "npm-normalize-package-bin": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "npm-packlist": { "version": "1.4.8", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1", @@ -32741,8 +32504,7 @@ "npmlog": { "version": "4.1.2", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -32753,20 +32515,17 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "object-assign": { "version": "4.1.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "once": { "version": "1.4.0", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "wrappy": "1" } @@ -32774,20 +32533,17 @@ "os-homedir": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "os-tmpdir": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "osenv": { "version": "0.1.5", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -32796,20 +32552,17 @@ "path-is-absolute": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "process-nextick-args": { "version": "2.0.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "rc": { "version": "1.2.8", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -32820,8 +32573,7 @@ "readable-stream": { "version": "2.3.7", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -32835,8 +32587,7 @@ "rimraf": { "version": "2.7.1", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "glob": "^7.1.3" } @@ -32844,44 +32595,37 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "safer-buffer": { "version": "2.1.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "sax": { "version": "1.2.4", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "semver": { "version": "5.7.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "set-blocking": { "version": "2.0.0", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "signal-exit": { "version": "3.0.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "string_decoder": { "version": "1.1.1", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "safe-buffer": "~5.1.0" } @@ -32889,8 +32633,7 @@ "string-width": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -32900,8 +32643,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "ansi-regex": "^2.0.0" } @@ -32909,14 +32651,12 @@ "strip-json-comments": { "version": "2.0.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "tar": { "version": "4.4.13", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", @@ -32930,14 +32670,12 @@ "util-deprecate": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "wide-align": { "version": "1.1.3", "bundled": true, - "dev": true, - "optional": true, + "extraneous": true, "requires": { "string-width": "^1.0.2 || 2" } @@ -32945,14 +32683,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "extraneous": true }, "yallist": { "version": "3.1.1", "bundled": true, - "dev": true, - "optional": true + "extraneous": true } } }, diff --git a/webapp/frontend/src/app/data/mock/device/details/sda.ts b/webapp/frontend/src/app/data/mock/device/details/sda.ts index 733e2ee..16b2d97 100644 --- a/webapp/frontend/src/app/data/mock/device/details/sda.ts +++ b/webapp/frontend/src/app/data/mock/device/details/sda.ts @@ -2,7 +2,7 @@ export const sda = { "data": { "device": { "CreatedAt": "2021-06-24T21:17:31.301226-07:00", - "UpdatedAt": "2021-06-26T14:26:20.856273-07:00", + "UpdatedAt": "2021-10-24T16:37:56.981833-07:00", "DeletedAt": null, "wwn": "0x5002538e40a22954", "device_name": "sda", @@ -23,7 +23,7 @@ export const sda = { "device_status": 0 }, "smart_results": [{ - "date": "2020-06-10T12:01:02Z", + "date": "2021-10-24T23:20:44Z", "device_wwn": "0x5002538e40a22954", "device_protocol": "NVMe", "temp": 36, @@ -32,211 +32,228 @@ export const sda = { "attrs": { "available_spare": { "attribute_id": "available_spare", - "name": "Available Spare", "value": 100, "thresh": 10, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "controller_busy_time": { "attribute_id": "controller_busy_time", - "name": "Controller Busy Time", "value": 3060, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "critical_comp_time": { "attribute_id": "critical_comp_time", - "name": "Critical CompTime", "value": 0, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "critical_warning": { "attribute_id": "critical_warning", - "name": "Critical Warning", "value": 0, "thresh": 0, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "data_units_read": { "attribute_id": "data_units_read", - "name": "Data Units Read", "value": 9511859, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "data_units_written": { "attribute_id": "data_units_written", - "name": "Data Units Written", "value": 7773431, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "host_reads": { "attribute_id": "host_reads", - "name": "Host Reads", "value": 111303174, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "host_writes": { "attribute_id": "host_writes", - "name": "Host Writes", "value": 83170961, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "media_errors": { "attribute_id": "media_errors", - "name": "Media Errors", "value": 0, "thresh": 0, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "num_err_log_entries": { "attribute_id": "num_err_log_entries", - "name": "Numb Err Log Entries", "value": 0, "thresh": 0, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "percentage_used": { "attribute_id": "percentage_used", - "name": "Percentage Used", "value": 0, "thresh": 100, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "power_cycles": { "attribute_id": "power_cycles", - "name": "Power Cycles", "value": 266, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "power_on_hours": { "attribute_id": "power_on_hours", - "name": "Power on Hours", "value": 2401, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "temperature": { "attribute_id": "temperature", - "name": "Temperature", "value": 36, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "unsafe_shutdowns": { "attribute_id": "unsafe_shutdowns", - "name": "Unsafe Shutdowns", "value": 43, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "warning_temp_time": { "attribute_id": "warning_temp_time", - "name": "Warning Temp Time", "value": 0, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 } - } + }, + "Status": 0 }] }, "metadata": { "available_spare": { + "display_name": "Available Spare", "ideal": "high", "critical": true, "description": "Contains a normalized percentage (0 to 100%) of the remaining spare capacity available.", "display_type": "" }, "controller_busy_time": { + "display_name": "Controller Busy Time", "ideal": "", "critical": false, "description": "Contains the amount of time the controller is busy with I/O commands. The controller is busy when there is a command outstanding to an I/O Queue (specifically, a command was issued via an I/O Submission Queue Tail doorbell write and the corresponding completion queue entry has not been posted yet to the associated I/O Completion Queue). This value is reported in minutes.", "display_type": "" }, "critical_comp_time": { + "display_name": "Critical CompTime", "ideal": "", "critical": false, "description": "Contains the amount of time in minutes that the controller is operational and the Composite Temperature is greater the Critical Composite Temperature Threshold (CCTEMP) field in the Identify Controller data structure.", "display_type": "" }, "critical_warning": { + "display_name": "Critical Warning", "ideal": "low", "critical": true, "description": "This field indicates critical warnings for the state of the controller. Each bit corresponds to a critical warning type; multiple bits may be set. If a bit is cleared to ‘0’, then that critical warning does not apply. Critical warnings may result in an asynchronous event notification to the host. Bits in this field represent the current associated state and are not persistent.", "display_type": "" }, "data_units_read": { + "display_name": "Data Units Read", "ideal": "", "critical": false, "description": "Contains the number of 512 byte data units the host has read from the controller; this value does not include metadata. This value is reported in thousands (i.e., a value of 1 corresponds to 1000 units of 512 bytes read) and is rounded up. When the LBA size is a value other than 512 bytes, the controller shall convert the amount of data read to 512 byte units.", "display_type": "" }, "data_units_written": { + "display_name": "Data Units Written", "ideal": "", "critical": false, "description": "Contains the number of 512 byte data units the host has written to the controller; this value does not include metadata. This value is reported in thousands (i.e., a value of 1 corresponds to 1000 units of 512 bytes written) and is rounded up. When the LBA size is a value other than 512 bytes, the controller shall convert the amount of data written to 512 byte units.", "display_type": "" }, "host_reads": { + "display_name": "Host Reads", "ideal": "", "critical": false, "description": "Contains the number of read commands completed by the controller", "display_type": "" }, "host_writes": { + "display_name": "Host Writes", "ideal": "", "critical": false, "description": "Contains the number of write commands completed by the controller", "display_type": "" }, "media_errors": { + "display_name": "Media Errors", "ideal": "low", "critical": true, "description": "Contains the number of occurrences where the controller detected an unrecovered data integrity error. Errors such as uncorrectable ECC, CRC checksum failure, or LBA tag mismatch are included in this field.", "display_type": "" }, "num_err_log_entries": { + "display_name": "Numb Err Log Entries", "ideal": "low", "critical": true, "description": "Contains the number of Error Information log entries over the life of the controller.", "display_type": "" }, "percentage_used": { + "display_name": "Percentage Used", "ideal": "low", "critical": true, "description": "Contains a vendor specific estimate of the percentage of NVM subsystem life used based on the actual usage and the manufacturer’s prediction of NVM life. A value of 100 indicates that the estimated endurance of the NVM in the NVM subsystem has been consumed, but may not indicate an NVM subsystem failure. The value is allowed to exceed 100. Percentages greater than 254 shall be represented as 255. This value shall be updated once per power-on hour (when the controller is not in a sleep state).", "display_type": "" }, "power_cycles": { + "display_name": "Power Cycles", "ideal": "", "critical": false, "description": "Contains the number of power cycles.", "display_type": "" }, "power_on_hours": { + "display_name": "Power on Hours", "ideal": "", "critical": false, "description": "Contains the number of power-on hours. Power on hours is always logging, even when in low power mode.", "display_type": "" }, "temperature": { + "display_name": "Temperature", "ideal": "", "critical": false, "description": "", "display_type": "" }, "unsafe_shutdowns": { + "display_name": "Unsafe Shutdowns", "ideal": "", "critical": false, "description": "Contains the number of unsafe shutdowns. This count is incremented when a shutdown notification (CC.SHN) is not received prior to loss of power.", "display_type": "" }, "warning_temp_time": { + "display_name": "Warning Temp Time", "ideal": "", "critical": false, "description": "Contains the amount of time in minutes that the controller is operational and the Composite Temperature is greater than or equal to the Warning Composite Temperature Threshold (WCTEMP) field and less than the Critical Composite Temperature Threshold (CCTEMP) field in the Identify Controller data structure.", diff --git a/webapp/frontend/src/app/data/mock/device/details/sdb.ts b/webapp/frontend/src/app/data/mock/device/details/sdb.ts index e658e79..5e817bd 100644 --- a/webapp/frontend/src/app/data/mock/device/details/sdb.ts +++ b/webapp/frontend/src/app/data/mock/device/details/sdb.ts @@ -2,7 +2,7 @@ export const sdb = { "data": { "device": { "CreatedAt": "2021-06-24T21:17:31.302191-07:00", - "UpdatedAt": "2021-06-27T09:25:21.627183-07:00", + "UpdatedAt": "2021-10-24T17:06:39.436996-07:00", "DeletedAt": null, "wwn": "0x5000cca264eb01d7", "device_name": "sdb", @@ -20,10 +20,10 @@ export const sdb = { "device_type": "", "label": "", "host_id": "", - "device_status": 0 + "device_status": 2 }, "smart_results": [{ - "date": "2020-06-21T00:03:30Z", + "date": "2021-10-24T20:34:04Z", "device_wwn": "0x5000cca264eb01d7", "device_protocol": "ATA", "temp": 32, @@ -32,205 +32,218 @@ export const sdb = { "attrs": { "1": { "attribute_id": 1, - "name": "Read Error Rate", "value": 100, "thresh": 1, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.034155719633986996 }, "10": { "attribute_id": 10, - "name": "Spin Retry Count", "value": 100, "thresh": 1, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.05459827163896099 }, "12": { "attribute_id": 12, - "name": "Power Cycle Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 9, "raw_string": "9", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.019835987118930823 }, "192": { "attribute_id": 192, - "name": "Power-off Retract Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 329, "raw_string": "329", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.01634692899031039 }, "193": { "attribute_id": 193, - "name": "Load Cycle Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 329, "raw_string": "329", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "194": { "attribute_id": 194, - "name": "Temperature", "value": 51, "thresh": 0, "worst": 51, "raw_value": 163210330144, "raw_string": "32 (Min/Max 24/38)", "when_failed": "", - "transformed_value": 0 + "transformed_value": 32, + "status": 0 }, "196": { "attribute_id": 196, - "name": "Reallocation Event Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.007389855800729792 }, "197": { "attribute_id": 197, - "name": "Current Pending Sector Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.025540791394761345 }, "198": { "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.028675322159886437 }, "199": { "attribute_id": 199, - "name": "UltraDMA CRC Error Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "2": { "attribute_id": 2, - "name": "Throughput Performance", "value": 135, "thresh": 54, "worst": 135, "raw_value": 108, "raw_string": "108", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "22": { "attribute_id": 22, - "name": "Current Helium Level", "value": 100, "thresh": 25, "worst": 100, "raw_value": 100, "raw_string": "100", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "3": { "attribute_id": 3, - "name": "Spin-Up Time", "value": 81, "thresh": 1, "worst": 81, "raw_value": 30089675132, "raw_string": "380 (Average 380)", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 2, + "status_reason": "Observed Failure Rate for Attribute is greater than 10%", + "failure_rate": 0.11452195377351217 }, "4": { "attribute_id": 4, - "name": "Start/Stop Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 9, "raw_string": "9", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.01989335424860646 }, "5": { "attribute_id": 5, - "name": "Reallocated Sectors Count", "value": 100, "thresh": 1, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.025169175350572493 }, "7": { "attribute_id": 7, - "name": "Seek Error Rate", "value": 100, "thresh": 1, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.01087335627722523 }, "8": { "attribute_id": 8, - "name": "Seek Time Performance", "value": 133, "thresh": 20, "worst": 133, "raw_value": 18, "raw_string": "18", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "9": { "attribute_id": 9, - "name": "Power-On Hours", "value": 100, "thresh": 0, "worst": 100, "raw_value": 1730, "raw_string": "1730", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 } - } + }, + "Status": 0 }, { - "date": "2021-01-23T16:24:06Z", + "date": "2021-10-24T23:20:44Z", "device_wwn": "0x5000cca264eb01d7", "device_protocol": "ATA", "temp": 32, @@ -239,414 +252,221 @@ export const sdb = { "attrs": { "1": { "attribute_id": 1, - "name": "Read Error Rate", "value": 100, "thresh": 1, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.034155719633986996 }, "10": { "attribute_id": 10, - "name": "Spin Retry Count", "value": 100, "thresh": 1, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.05459827163896099 }, "12": { "attribute_id": 12, - "name": "Power Cycle Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 9, "raw_string": "9", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.019835987118930823 }, "192": { "attribute_id": 192, - "name": "Power-off Retract Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 329, "raw_string": "329", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.01634692899031039 }, "193": { "attribute_id": 193, - "name": "Load Cycle Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 329, "raw_string": "329", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "194": { "attribute_id": 194, - "name": "Temperature", "value": 51, "thresh": 0, "worst": 51, "raw_value": 163210330144, "raw_string": "32 (Min/Max 24/38)", "when_failed": "", - "transformed_value": 0 + "transformed_value": 32, + "status": 0 }, "196": { "attribute_id": 196, - "name": "Reallocation Event Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.007389855800729792 }, "197": { "attribute_id": 197, - "name": "Current Pending Sector Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.025540791394761345 }, "198": { "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.028675322159886437 }, "199": { "attribute_id": 199, - "name": "UltraDMA CRC Error Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "2": { "attribute_id": 2, - "name": "Throughput Performance", "value": 135, "thresh": 54, "worst": 135, "raw_value": 108, "raw_string": "108", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "22": { "attribute_id": 22, - "name": "Current Helium Level", "value": 100, "thresh": 25, "worst": 100, "raw_value": 100, "raw_string": "100", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "3": { "attribute_id": 3, - "name": "Spin-Up Time", "value": 81, "thresh": 1, "worst": 81, "raw_value": 30089675132, "raw_string": "380 (Average 380)", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 2, + "status_reason": "Observed Failure Rate for Attribute is greater than 10%", + "failure_rate": 0.11452195377351217 }, "4": { "attribute_id": 4, - "name": "Start/Stop Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 9, "raw_string": "9", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.01989335424860646 }, "5": { "attribute_id": 5, - "name": "Reallocated Sectors Count", "value": 100, "thresh": 1, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.025169175350572493 }, "7": { "attribute_id": 7, - "name": "Seek Error Rate", "value": 100, "thresh": 1, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.01087335627722523 }, "8": { "attribute_id": 8, - "name": "Seek Time Performance", "value": 133, "thresh": 20, "worst": 133, "raw_value": 18, "raw_string": "18", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "9": { "attribute_id": 9, - "name": "Power-On Hours", "value": 100, "thresh": 0, "worst": 100, "raw_value": 1730, "raw_string": "1730", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 } - } - }, { - "date": "2021-01-23T16:25:46Z", - "device_wwn": "0x5000cca264eb01d7", - "device_protocol": "ATA", - "temp": 32, - "power_on_hours": 1730, - "power_cycle_count": 9, - "attrs": { - "1": { - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "thresh": 1, - "worst": 100, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, - "10": { - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "thresh": 1, - "worst": 100, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, - "12": { - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "thresh": 0, - "worst": 100, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, - "192": { - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "thresh": 0, - "worst": 100, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, - "193": { - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "thresh": 0, - "worst": 100, - "raw_value": 329, - "raw_string": "329", - "when_failed": "", - "transformed_value": 0 - }, - "194": { - "attribute_id": 194, - "name": "Temperature", - "value": 51, - "thresh": 0, - "worst": 51, - "raw_value": 163210330144, - "raw_string": "32 (Min/Max 24/38)", - "when_failed": "", - "transformed_value": 0 - }, - "196": { - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 100, - "thresh": 0, - "worst": 100, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, - "197": { - "attribute_id": 197, - "name": "Current Pending Sector Count", - "value": 100, - "thresh": 0, - "worst": 100, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, - "198": { - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", - "value": 100, - "thresh": 0, - "worst": 100, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, - "199": { - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", - "value": 100, - "thresh": 0, - "worst": 100, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, - "2": { - "attribute_id": 2, - "name": "Throughput Performance", - "value": 135, - "thresh": 54, - "worst": 135, - "raw_value": 108, - "raw_string": "108", - "when_failed": "", - "transformed_value": 0 - }, - "22": { - "attribute_id": 22, - "name": "Current Helium Level", - "value": 100, - "thresh": 25, - "worst": 100, - "raw_value": 100, - "raw_string": "100", - "when_failed": "", - "transformed_value": 0 - }, - "3": { - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 81, - "thresh": 1, - "worst": 81, - "raw_value": 30089675132, - "raw_string": "380 (Average 380)", - "when_failed": "", - "transformed_value": 0 - }, - "4": { - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "thresh": 0, - "worst": 100, - "raw_value": 9, - "raw_string": "9", - "when_failed": "", - "transformed_value": 0 - }, - "5": { - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "thresh": 1, - "worst": 100, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, - "7": { - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "thresh": 1, - "worst": 100, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, - "8": { - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 133, - "thresh": 20, - "worst": 133, - "raw_value": 18, - "raw_string": "18", - "when_failed": "", - "transformed_value": 0 - }, - "9": { - "attribute_id": 9, - "name": "Power-On Hours", - "value": 100, - "thresh": 0, - "worst": 100, - "raw_value": 1730, - "raw_string": "1730", - "when_failed": "", - "transformed_value": 0 - } - } + }, + "Status": 0 }] }, "metadata": { "1": { + "display_name": "Read Error Rate", "ideal": "low", "critical": false, "description": "(Vendor specific raw value.) Stores data related to the rate of hardware read errors that occurred when reading data from a disk surface. The raw value has different structure for different vendors and is often not meaningful as a decimal number.", @@ -694,6 +514,7 @@ export const sdb = { "display_type": "normalized" }, "10": { + "display_name": "Spin Retry Count", "ideal": "low", "critical": true, "description": "Count of retry of spin start attempts. This attribute stores a total count of the spin start attempts to reach the fully operational speed (under the condition that the first attempt was unsuccessful). An increase of this attribute value is a sign of problems in the hard disk mechanical subsystem.", @@ -711,6 +532,7 @@ export const sdb = { "display_type": "raw" }, "11": { + "display_name": "Recalibration Retries or Calibration Retry Count", "ideal": "low", "critical": false, "description": "This attribute indicates the count that recalibration was requested (under the condition that the first attempt was unsuccessful). An increase of this attribute value is a sign of problems in the hard disk mechanical subsystem.", @@ -758,6 +580,7 @@ export const sdb = { "display_type": "raw" }, "12": { + "display_name": "Power Cycle Count", "ideal": "low", "critical": false, "description": "This attribute indicates the count of full hard disk power on/off cycles.", @@ -800,84 +623,98 @@ export const sdb = { "display_type": "raw" }, "13": { + "display_name": "Soft Read Error Rate", "ideal": "low", "critical": false, "description": "Uncorrected read errors reported to the operating system.", "display_type": "normalized" }, "170": { + "display_name": "Available Reserved Space", "ideal": "", "critical": false, "description": "See attribute E8.", "display_type": "normalized" }, "171": { + "display_name": "SSD Program Fail Count", "ideal": "", "critical": false, "description": "(Kingston) The total number of flash program operation failures since the drive was deployed.[33] Identical to attribute 181.", "display_type": "normalized" }, "172": { + "display_name": "SSD Erase Fail Count", "ideal": "", "critical": false, "description": "(Kingston) Counts the number of flash erase failures. This attribute returns the total number of Flash erase operation failures since the drive was deployed. This attribute is identical to attribute 182.", "display_type": "normalized" }, "173": { + "display_name": "SSD Wear Leveling Count", "ideal": "", "critical": false, "description": "Counts the maximum worst erase count on any block.", "display_type": "normalized" }, "174": { + "display_name": "Unexpected Power Loss Count", "ideal": "", "critical": false, "description": "Also known as \"Power-off Retract Count\" per conventional HDD terminology. Raw value reports the number of unclean shutdowns, cumulative over the life of an SSD, where an \"unclean shutdown\" is the removal of power without STANDBY IMMEDIATE as the last command (regardless of PLI activity using capacitor power). Normalized value is always 100.", "display_type": "" }, "175": { + "display_name": "Power Loss Protection Failure", "ideal": "", "critical": false, "description": "Last test result as microseconds to discharge cap, saturated at its maximum value. Also logs minutes since last test and lifetime number of tests. Raw value contains the following data: Bytes 0-1: Last test result as microseconds to discharge cap, saturates at max value. Test result expected in range 25 \u003c= result \u003c= 5000000, lower indicates specific error code. Bytes 2-3: Minutes since last test, saturates at max value.Bytes 4-5: Lifetime number of tests, not incremented on power cycle, saturates at max value. Normalized value is set to one on test failure or 11 if the capacitor has been tested in an excessive temperature condition, otherwise 100.", "display_type": "normalized" }, "176": { + "display_name": "Erase Fail Count", "ideal": "", "critical": false, "description": "S.M.A.R.T. parameter indicates a number of flash erase command failures.", "display_type": "normalized" }, "177": { + "display_name": "Wear Range Delta", "ideal": "", "critical": false, "description": "Delta between most-worn and least-worn Flash blocks. It describes how good/bad the wearleveling of the SSD works on a more technical way. ", "display_type": "normalized" }, "179": { + "display_name": "Used Reserved Block Count Total", "ideal": "", "critical": false, "description": "Pre-Fail attribute used at least in Samsung devices.", "display_type": "normalized" }, "180": { + "display_name": "Unused Reserved Block Count Total", "ideal": "", "critical": false, "description": "\"Pre-Fail\" attribute used at least in HP devices. ", "display_type": "normalized" }, "181": { + "display_name": "Program Fail Count Total", "ideal": "", "critical": false, "description": "Total number of Flash program operation failures since the drive was deployed.", "display_type": "normalized" }, "182": { + "display_name": "Erase Fail Count", "ideal": "", "critical": false, "description": "\"Pre-Fail\" Attribute used at least in Samsung devices.", "display_type": "normalized" }, "183": { + "display_name": "SATA Downshift Error Count or Runtime Bad Block", "ideal": "low", "critical": false, "description": "Western Digital, Samsung or Seagate attribute: Either the number of downshifts of link speed (e.g. from 6Gbit/s to 3Gbit/s) or the total number of data blocks with detected, uncorrectable errors encountered during normal operation. Although degradation of this parameter can be an indicator of drive aging and/or potential electromechanical problems, it does not directly indicate imminent drive failure.", @@ -930,6 +767,7 @@ export const sdb = { "display_type": "raw" }, "184": { + "display_name": "End-to-End error", "ideal": "low", "critical": true, "description": "This attribute is a part of Hewlett-Packard\"s SMART IV technology, as well as part of other vendors\" IO Error Detection and Correction schemas, and it contains a count of parity errors which occur in the data path to the media via the drive\"s cache RAM", @@ -977,18 +815,21 @@ export const sdb = { "display_type": "normalized" }, "185": { + "display_name": "Head Stability", "ideal": "", "critical": false, "description": "Western Digital attribute.", "display_type": "normalized" }, "186": { + "display_name": "Induced Op-Vibration Detection", "ideal": "", "critical": false, "description": "Western Digital attribute.", "display_type": "normalized" }, "187": { + "display_name": "Reported Uncorrectable Errors", "ideal": "low", "critical": true, "description": "The count of errors that could not be recovered using hardware ECC (see attribute 195).", @@ -1041,6 +882,7 @@ export const sdb = { "display_type": "raw" }, "188": { + "display_name": "Command Timeout", "ideal": "low", "critical": true, "description": "The count of aborted operations due to HDD timeout. Normally this attribute value should be equal to zero.", @@ -1093,6 +935,7 @@ export const sdb = { "display_type": "raw" }, "189": { + "display_name": "High Fly Writes", "ideal": "low", "critical": false, "description": "HDD manufacturers implement a flying height sensor that attempts to provide additional protections for write operations by detecting when a recording head is flying outside its normal operating range. If an unsafe fly height condition is encountered, the write process is stopped, and the information is rewritten or reallocated to a safe region of the hard drive. This attribute indicates the count of these errors detected over the lifetime of the drive.", @@ -1140,18 +983,21 @@ export const sdb = { "display_type": "raw" }, "190": { + "display_name": "Temperature Difference", "ideal": "", "critical": false, "description": "Value is equal to (100-temp. °C), allowing manufacturer to set a minimum threshold which corresponds to a maximum temperature. This also follows the convention of 100 being a best-case value and lower values being undesirable. However, some older drives may instead report raw Temperature (identical to 0xC2) or Temperature minus 50 here.", "display_type": "normalized" }, "191": { + "display_name": "G-sense Error Rate", "ideal": "low", "critical": false, "description": "The count of errors resulting from externally induced shock and vibration. ", "display_type": "normalized" }, "192": { + "display_name": "Power-off Retract Count", "ideal": "low", "critical": false, "description": "Number of power-off or emergency retract cycles.", @@ -1199,12 +1045,14 @@ export const sdb = { "display_type": "raw" }, "193": { + "display_name": "Load Cycle Count", "ideal": "low", "critical": false, "description": "Count of load/unload cycles into head landing zone position.[45] Some drives use 225 (0xE1) for Load Cycle Count instead.", "display_type": "normalized" }, "194": { + "display_name": "Temperature", "ideal": "low", "critical": false, "description": "Indicates the device temperature, if the appropriate sensor is fitted. Lowest byte of the raw value contains the exact temperature value (Celsius degrees).", @@ -1212,6 +1060,7 @@ export const sdb = { "display_type": "transformed" }, "195": { + "display_name": "Hardware ECC Recovered", "ideal": "", "critical": false, "description": "(Vendor-specific raw value.) The raw value has different structure for different vendors and is often not meaningful as a decimal number.", @@ -1259,6 +1108,7 @@ export const sdb = { "display_type": "normalized" }, "196": { + "display_name": "Reallocation Event Count", "ideal": "low", "critical": true, "description": "Count of remap operations. The raw value of this attribute shows the total count of attempts to transfer data from reallocated sectors to a spare area. Both successful and unsuccessful attempts are counted.", @@ -1311,6 +1161,7 @@ export const sdb = { "display_type": "raw" }, "197": { + "display_name": "Current Pending Sector Count", "ideal": "low", "critical": true, "description": "Count of \"unstable\" sectors (waiting to be remapped, because of unrecoverable read errors). If an unstable sector is subsequently read successfully, the sector is remapped and this value is decreased. Read errors on a sector will not remap the sector immediately (since the correct value cannot be read and so the value to remap is not known, and also it might become readable later); instead, the drive firmware remembers that the sector needs to be remapped, and will remap it the next time it\"s written.", @@ -1363,6 +1214,7 @@ export const sdb = { "display_type": "raw" }, "198": { + "display_name": "(Offline) Uncorrectable Sector Count", "ideal": "low", "critical": true, "description": "The total count of uncorrectable errors when reading/writing a sector. A rise in the value of this attribute indicates defects of the disk surface and/or problems in the mechanical subsystem.", @@ -1415,6 +1267,7 @@ export const sdb = { "display_type": "raw" }, "199": { + "display_name": "UltraDMA CRC Error Count", "ideal": "low", "critical": false, "description": "The count of errors in data transfer via the interface cable as determined by ICRC (Interface Cyclic Redundancy Check).", @@ -1467,246 +1320,287 @@ export const sdb = { "display_type": "raw" }, "2": { + "display_name": "Throughput Performance", "ideal": "high", "critical": false, "description": "Overall (general) throughput performance of a hard disk drive. If the value of this attribute is decreasing there is a high probability that there is a problem with the disk.", "display_type": "normalized" }, "200": { + "display_name": "Multi-Zone Error Rate", "ideal": "low", "critical": false, "description": "The count of errors found when writing a sector. The higher the value, the worse the disk\"s mechanical condition is.", "display_type": "normalized" }, "201": { + "display_name": "Soft Read Error Rate", "ideal": "low", "critical": true, "description": "Count indicates the number of uncorrectable software read errors.", "display_type": "normalized" }, "202": { + "display_name": "Data Address Mark errors", "ideal": "low", "critical": false, "description": "Count of Data Address Mark errors (or vendor-specific).", "display_type": "normalized" }, "203": { + "display_name": "Run Out Cancel", "ideal": "low", "critical": false, "description": "The number of errors caused by incorrect checksum during the error correction.", "display_type": "normalized" }, "204": { + "display_name": "Soft ECC Correction", "ideal": "low", "critical": false, "description": "Count of errors corrected by the internal error correction software.", "display_type": "" }, "205": { + "display_name": "Thermal Asperity Rate", "ideal": "low", "critical": false, "description": "Count of errors due to high temperature.", "display_type": "normalized" }, "206": { + "display_name": "Flying Height", "ideal": "", "critical": false, "description": "Height of heads above the disk surface. If too low, head crash is more likely; if too high, read/write errors are more likely.", "display_type": "normalized" }, "207": { + "display_name": "Spin High Current", "ideal": "low", "critical": false, "description": "Amount of surge current used to spin up the drive.", "display_type": "normalized" }, "208": { + "display_name": "Spin Buzz", "ideal": "", "critical": false, "description": "Count of buzz routines needed to spin up the drive due to insufficient power.", "display_type": "normalized" }, "209": { + "display_name": "Offline Seek Performance", "ideal": "", "critical": false, "description": "Drive\"s seek performance during its internal tests.", "display_type": "normalized" }, "210": { + "display_name": "Vibration During Write", "ideal": "", "critical": false, "description": "Found in Maxtor 6B200M0 200GB and Maxtor 2R015H1 15GB disks.", "display_type": "normalized" }, "211": { + "display_name": "Vibration During Write", "ideal": "", "critical": false, "description": "A recording of a vibration encountered during write operations.", "display_type": "normalized" }, "212": { + "display_name": "Shock During Write", "ideal": "", "critical": false, "description": "A recording of shock encountered during write operations.", "display_type": "normalized" }, "22": { + "display_name": "Current Helium Level", "ideal": "high", "critical": false, "description": "Specific to He8 drives from HGST. This value measures the helium inside of the drive specific to this manufacturer. It is a pre-fail attribute that trips once the drive detects that the internal environment is out of specification.", "display_type": "normalized" }, "220": { + "display_name": "Disk Shift", "ideal": "low", "critical": false, "description": "Distance the disk has shifted relative to the spindle (usually due to shock or temperature). Unit of measure is unknown.", "display_type": "normalized" }, "221": { + "display_name": "G-Sense Error Rate", "ideal": "low", "critical": false, "description": "The count of errors resulting from externally induced shock and vibration.", "display_type": "normalized" }, "222": { + "display_name": "Loaded Hours", "ideal": "", "critical": false, "description": "Time spent operating under data load (movement of magnetic head armature).", "display_type": "normalized" }, "223": { + "display_name": "Load/Unload Retry Count", "ideal": "", "critical": false, "description": "Count of times head changes position.", "display_type": "normalized" }, "224": { + "display_name": "Load Friction", "ideal": "low", "critical": false, "description": "Resistance caused by friction in mechanical parts while operating.", "display_type": "normalized" }, "225": { + "display_name": "Load/Unload Cycle Count", "ideal": "low", "critical": false, "description": "Total count of load cycles Some drives use 193 (0xC1) for Load Cycle Count instead. See Description for 193 for significance of this number. ", "display_type": "normalized" }, "226": { + "display_name": "Load \"In\"-time", "ideal": "", "critical": false, "description": "Total time of loading on the magnetic heads actuator (time not spent in parking area).", "display_type": "normalized" }, "227": { + "display_name": "Torque Amplification Count", "ideal": "low", "critical": false, "description": "Count of attempts to compensate for platter speed variations.[66]", "display_type": "" }, "228": { + "display_name": "Power-Off Retract Cycle", "ideal": "low", "critical": false, "description": "The number of power-off cycles which are counted whenever there is a \"retract event\" and the heads are loaded off of the media such as when the machine is powered down, put to sleep, or is idle.", "display_type": "" }, "230": { + "display_name": "GMR Head Amplitude ", "ideal": "", "critical": false, "description": "Amplitude of \"thrashing\" (repetitive head moving motions between operations).", "display_type": "normalized" }, "231": { + "display_name": "Life Left", "ideal": "", "critical": false, "description": "Indicates the approximate SSD life left, in terms of program/erase cycles or available reserved blocks. A normalized value of 100 represents a new drive, with a threshold value at 10 indicating a need for replacement. A value of 0 may mean that the drive is operating in read-only mode to allow data recovery.", "display_type": "normalized" }, "232": { + "display_name": "Endurance Remaining", "ideal": "", "critical": false, "description": "Number of physical erase cycles completed on the SSD as a percentage of the maximum physical erase cycles the drive is designed to endure.", "display_type": "normalized" }, "233": { + "display_name": "Media Wearout Indicator", "ideal": "", "critical": false, "description": "Intel SSDs report a normalized value from 100, a new drive, to a minimum of 1. It decreases while the NAND erase cycles increase from 0 to the maximum-rated cycles.", "display_type": "normalized" }, "234": { + "display_name": "Average erase count", "ideal": "", "critical": false, "description": "Decoded as: byte 0-1-2 = average erase count (big endian) and byte 3-4-5 = max erase count (big endian).", "display_type": "normalized" }, "235": { + "display_name": "Good Block Count", "ideal": "", "critical": false, "description": "Decoded as: byte 0-1-2 = good block count (big endian) and byte 3-4 = system (free) block count.", "display_type": "normalized" }, "240": { + "display_name": "Head Flying Hours", "ideal": "", "critical": false, "description": "Time spent during the positioning of the drive heads.[15][71] Some Fujitsu drives report the count of link resets during a data transfer.", "display_type": "normalized" }, "241": { + "display_name": "Total LBAs Written", "ideal": "", "critical": false, "description": "Total count of LBAs written.", "display_type": "normalized" }, "242": { + "display_name": "Total LBAs Read", "ideal": "", "critical": false, "description": "Total count of LBAs read.Some S.M.A.R.T. utilities will report a negative number for the raw value since in reality it has 48 bits rather than 32.", "display_type": "normalized" }, "243": { + "display_name": "Total LBAs Written Expanded", "ideal": "", "critical": false, "description": "The upper 5 bytes of the 12-byte total number of LBAs written to the device. The lower 7 byte value is located at attribute 0xF1.", "display_type": "normalized" }, "244": { + "display_name": "Total LBAs Read Expanded", "ideal": "", "critical": false, "description": "The upper 5 bytes of the 12-byte total number of LBAs read from the device. The lower 7 byte value is located at attribute 0xF2.", "display_type": "normalized" }, "249": { + "display_name": "NAND Writes (1GiB)", "ideal": "", "critical": false, "description": "Total NAND Writes. Raw value reports the number of writes to NAND in 1 GB increments.", "display_type": "normalized" }, "250": { + "display_name": "Read Error Retry Rate", "ideal": "low", "critical": false, "description": "Count of errors while reading from a disk.", "display_type": "normalized" }, "251": { + "display_name": "Minimum Spares Remaining", "ideal": "", "critical": false, "description": "The Minimum Spares Remaining attribute indicates the number of remaining spare blocks as a percentage of the total number of spare blocks available.", "display_type": "normalized" }, "252": { + "display_name": "Newly Added Bad Flash Block", "ideal": "", "critical": false, "description": "The Newly Added Bad Flash Block attribute indicates the total number of bad flash blocks the drive detected since it was first initialized in manufacturing.", "display_type": "normalized" }, "254": { + "display_name": "Free Fall Protection", "ideal": "low", "critical": false, "description": "Count of \"Free Fall Events\" detected.", "display_type": "normalized" }, "3": { + "display_name": "Spin-Up Time", "ideal": "low", "critical": false, "description": "Average time of spindle spin up (from zero RPM to fully operational [milliseconds]).", @@ -1754,6 +1648,7 @@ export const sdb = { "display_type": "normalized" }, "4": { + "display_name": "Start/Stop Count", "ideal": "", "critical": false, "description": "A tally of spindle start/stop cycles. The spindle turns on, and hence the count is increased, both when the hard disk is turned on after having before been turned entirely off (disconnected from power source) and when the hard disk returns from having previously been put to sleep mode.", @@ -1801,6 +1696,7 @@ export const sdb = { "display_type": "raw" }, "5": { + "display_name": "Reallocated Sectors Count", "ideal": "low", "critical": true, "description": "Count of reallocated sectors. The raw value represents a count of the bad sectors that have been found and remapped.Thus, the higher the attribute value, the more sectors the drive has had to reallocate. This value is primarily used as a metric of the life expectancy of the drive; a drive which has had any reallocations at all is significantly more likely to fail in the immediate months.", @@ -1853,12 +1749,14 @@ export const sdb = { "display_type": "raw" }, "6": { + "display_name": "Read Channel Margin", "ideal": "", "critical": false, "description": "Margin of a channel while reading data. The function of this attribute is not specified.", "display_type": "normalized" }, "7": { + "display_name": "Seek Error Rate", "ideal": "", "critical": false, "description": "(Vendor specific raw value.) Rate of seek errors of the magnetic heads. If there is a partial failure in the mechanical positioning system, then seek errors will arise. Such a failure may be due to numerous factors, such as damage to a servo, or thermal widening of the hard disk. The raw value has different structure for different vendors and is often not meaningful as a decimal number.", @@ -1906,12 +1804,14 @@ export const sdb = { "display_type": "normalized" }, "8": { + "display_name": "Seek Time Performance", "ideal": "high", "critical": false, "description": "Average performance of seek operations of the magnetic heads. If this attribute is decreasing, it is a sign of problems in the mechanical subsystem.", "display_type": "normalized" }, "9": { + "display_name": "Power-On Hours", "ideal": "", "critical": false, "description": "Count of hours in power-on state. The raw value of this attribute shows total count of hours (or minutes, or seconds, depending on manufacturer) in power-on state. By default, the total expected lifetime of a hard disk in perfect condition is defined as 5 years (running every day and night on all days). This is equal to 1825 days in 24/7 mode or 43800 hours. On some pre-2005 drives, this raw value may advance erratically and/or \"wrap around\" (reset to zero periodically).", diff --git a/webapp/frontend/src/app/data/mock/device/details/sdc.ts b/webapp/frontend/src/app/data/mock/device/details/sdc.ts index 692437f..66fa65d 100644 --- a/webapp/frontend/src/app/data/mock/device/details/sdc.ts +++ b/webapp/frontend/src/app/data/mock/device/details/sdc.ts @@ -2,7 +2,7 @@ export const sdc = { "data": { "device": { "CreatedAt": "2021-06-24T21:17:31.303033-07:00", - "UpdatedAt": "2021-06-26T14:26:20.449968-07:00", + "UpdatedAt": "2021-10-24T16:37:56.74865-07:00", "DeletedAt": null, "wwn": "0x5000cca264ec3183", "device_name": "sdc", @@ -20,10 +20,10 @@ export const sdc = { "device_type": "", "label": "", "host_id": "", - "device_status": 1 + "device_status": 3 }, "smart_results": [{ - "date": "2020-07-08T13:48:23Z", + "date": "2021-10-24T23:20:44Z", "device_wwn": "0x5000cca264ec3183", "device_protocol": "ATA", "temp": 25, @@ -32,393 +32,212 @@ export const sdc = { "attrs": { "1": { "attribute_id": 1, - "name": "Read Error Rate", "value": 100, "thresh": 16, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 - }, - "10": { - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "thresh": 60, - "worst": 100, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", "transformed_value": 0, - "status": "passed" - }, - "12": { - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "thresh": 0, - "worst": 100, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }, - "192": { - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 95, - "thresh": 0, - "worst": 95, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }, - "193": { - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 95, - "thresh": 0, - "worst": 95, - "raw_value": 6244, - "raw_string": "6244", - "when_failed": "", - "transformed_value": 0 - }, - "194": { - "attribute_id": 194, - "name": "Temperature", - "value": 240, - "thresh": 0, - "worst": 240, - "raw_value": 167504969753, - "raw_string": "25 (Min/Max 19/39)", - "when_failed": "", - "transformed_value": 0 - }, - "196": { - "attribute_id": 196, - "name": "Reallocation Event Count", - "value": 1, - "thresh": 0, - "worst": 1, - "raw_value": 3831, - "raw_string": "3831", - "when_failed": "", - "transformed_value": 0 - }, - "197": { - "attribute_id": 197, - "name": "Current Pending Sector Count", - "value": 100, - "thresh": 0, - "worst": 100, - "raw_value": 8, - "raw_string": "8", - "when_failed": "", - "transformed_value": 0 - }, - "198": { - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", - "value": 100, - "thresh": 0, - "worst": 100, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, - "199": { - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", - "value": 200, - "thresh": 0, - "worst": 200, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, - "2": { - "attribute_id": 2, - "name": "Throughput Performance", - "value": 136, - "thresh": 54, - "worst": 136, - "raw_value": 91, - "raw_string": "91", - "when_failed": "", - "transformed_value": 0 - }, - "3": { - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 125, - "thresh": 24, - "worst": 125, - "raw_value": 17192124596, - "raw_string": "180 (Average 187)", - "when_failed": "", - "transformed_value": 0 - }, - "4": { - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "thresh": 0, - "worst": 100, - "raw_value": 86, - "raw_string": "86", - "when_failed": "", - "transformed_value": 0 - }, - "5": { - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 1, - "thresh": 5, - "worst": 1, - "raw_value": 1975, - "raw_string": "1975", - "when_failed": "now", - "transformed_value": 0 - }, - "7": { - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 100, - "thresh": 67, - "worst": 100, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 - }, - "8": { - "attribute_id": 8, - "name": "Seek Time Performance", - "value": 118, - "thresh": 20, - "worst": 118, - "raw_value": 33, - "raw_string": "33", - "when_failed": "", - "transformed_value": 0 - }, - "9": { - "attribute_id": 9, - "name": "Power-On Hours", - "value": 91, - "thresh": 0, - "worst": 91, - "raw_value": 65592, - "raw_string": "65592", - "when_failed": "", - "transformed_value": 0 - } - } - }, { - "date": "2020-07-08T13:48:23Z", - "device_wwn": "0x5000cca264ec3183", - "device_protocol": "ATA", - "temp": 25, - "power_on_hours": 65592, - "power_cycle_count": 86, - "attrs": { - "1": { - "attribute_id": 1, - "name": "Read Error Rate", - "value": 100, - "thresh": 16, - "worst": 100, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0 + "status": 0, + "failure_rate": 0.034155719633986996 }, "10": { "attribute_id": 10, - "name": "Spin Retry Count", "value": 100, "thresh": 60, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.05459827163896099 }, "12": { "attribute_id": 12, - "name": "Power Cycle Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 86, "raw_string": "86", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 2, + "status_reason": "Observed Failure Rate for Attribute is greater than 10%", + "failure_rate": 0.12354840389522469 }, "192": { "attribute_id": 192, - "name": "Power-off Retract Count", "value": 95, "thresh": 0, "worst": 95, "raw_value": 6244, "raw_string": "6244", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "193": { "attribute_id": 193, - "name": "Load Cycle Count", "value": 95, "thresh": 0, "worst": 95, "raw_value": 6244, "raw_string": "6244", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "194": { "attribute_id": 194, - "name": "Temperature", "value": 240, "thresh": 0, "worst": 240, "raw_value": 167504969753, "raw_string": "25 (Min/Max 19/39)", "when_failed": "", - "transformed_value": 0 + "transformed_value": 25, + "status": 0 }, "196": { "attribute_id": 196, - "name": "Reallocation Event Count", "value": 1, "thresh": 0, "worst": 1, "raw_value": 3831, "raw_string": "3831", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 2, + "status_reason": "Could not determine Observed Failure Rate for Critical Attribute" }, "197": { "attribute_id": 197, - "name": "Current Pending Sector Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 8, "raw_string": "8", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 1, + "status_reason": "Observed Failure Rate for Critical Attribute is greater than 10%", + "failure_rate": 0.6108100007493069 }, "198": { "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.028675322159886437 }, "199": { "attribute_id": 199, - "name": "UltraDMA CRC Error Count", "value": 200, "thresh": 0, "worst": 200, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "2": { "attribute_id": 2, - "name": "Throughput Performance", "value": 136, "thresh": 54, "worst": 136, "raw_value": 91, "raw_string": "91", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "3": { "attribute_id": 3, - "name": "Spin-Up Time", "value": 125, "thresh": 24, "worst": 125, "raw_value": 17192124596, "raw_string": "180 (Average 187)", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.009100406705780476 }, "4": { "attribute_id": 4, - "name": "Start/Stop Count", "value": 100, "thresh": 0, "worst": 100, "raw_value": 86, "raw_string": "86", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 2, + "status_reason": "Observed Failure Rate for Attribute is greater than 10%", + "failure_rate": 0.12262136155304391 }, "5": { "attribute_id": 5, - "name": "Reallocated Sectors Count", "value": 1, "thresh": 5, "worst": 1, "raw_value": 1975, "raw_string": "1975", "when_failed": "now", - "transformed_value": 0 + "transformed_value": 0, + "status": 1, + "status_reason": "Observed Failure Rate for Critical Attribute is greater than 10%", + "failure_rate": 1.5028253400346423 }, "7": { "attribute_id": 7, - "name": "Seek Error Rate", "value": 100, "thresh": 67, "worst": 100, "raw_value": 0, "raw_string": "0", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0, + "failure_rate": 0.01087335627722523 }, "8": { "attribute_id": 8, - "name": "Seek Time Performance", "value": 118, "thresh": 20, "worst": 118, "raw_value": 33, "raw_string": "33", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "9": { "attribute_id": 9, - "name": "Power-On Hours", "value": 91, "thresh": 0, "worst": 91, "raw_value": 65592, "raw_string": "65592", "when_failed": "", - "transformed_value": 0 + "transformed_value": 0, + "status": 0 } - } + }, + "Status": 0 }] }, "metadata": { "1": { + "display_name": "Read Error Rate", "ideal": "low", "critical": false, "description": "(Vendor specific raw value.) Stores data related to the rate of hardware read errors that occurred when reading data from a disk surface. The raw value has different structure for different vendors and is often not meaningful as a decimal number.", @@ -466,6 +285,7 @@ export const sdc = { "display_type": "normalized" }, "10": { + "display_name": "Spin Retry Count", "ideal": "low", "critical": true, "description": "Count of retry of spin start attempts. This attribute stores a total count of the spin start attempts to reach the fully operational speed (under the condition that the first attempt was unsuccessful). An increase of this attribute value is a sign of problems in the hard disk mechanical subsystem.", @@ -483,6 +303,7 @@ export const sdc = { "display_type": "raw" }, "11": { + "display_name": "Recalibration Retries or Calibration Retry Count", "ideal": "low", "critical": false, "description": "This attribute indicates the count that recalibration was requested (under the condition that the first attempt was unsuccessful). An increase of this attribute value is a sign of problems in the hard disk mechanical subsystem.", @@ -530,6 +351,7 @@ export const sdc = { "display_type": "raw" }, "12": { + "display_name": "Power Cycle Count", "ideal": "low", "critical": false, "description": "This attribute indicates the count of full hard disk power on/off cycles.", @@ -572,84 +394,98 @@ export const sdc = { "display_type": "raw" }, "13": { + "display_name": "Soft Read Error Rate", "ideal": "low", "critical": false, "description": "Uncorrected read errors reported to the operating system.", "display_type": "normalized" }, "170": { + "display_name": "Available Reserved Space", "ideal": "", "critical": false, "description": "See attribute E8.", "display_type": "normalized" }, "171": { + "display_name": "SSD Program Fail Count", "ideal": "", "critical": false, "description": "(Kingston) The total number of flash program operation failures since the drive was deployed.[33] Identical to attribute 181.", "display_type": "normalized" }, "172": { + "display_name": "SSD Erase Fail Count", "ideal": "", "critical": false, "description": "(Kingston) Counts the number of flash erase failures. This attribute returns the total number of Flash erase operation failures since the drive was deployed. This attribute is identical to attribute 182.", "display_type": "normalized" }, "173": { + "display_name": "SSD Wear Leveling Count", "ideal": "", "critical": false, "description": "Counts the maximum worst erase count on any block.", "display_type": "normalized" }, "174": { + "display_name": "Unexpected Power Loss Count", "ideal": "", "critical": false, "description": "Also known as \"Power-off Retract Count\" per conventional HDD terminology. Raw value reports the number of unclean shutdowns, cumulative over the life of an SSD, where an \"unclean shutdown\" is the removal of power without STANDBY IMMEDIATE as the last command (regardless of PLI activity using capacitor power). Normalized value is always 100.", "display_type": "" }, "175": { + "display_name": "Power Loss Protection Failure", "ideal": "", "critical": false, "description": "Last test result as microseconds to discharge cap, saturated at its maximum value. Also logs minutes since last test and lifetime number of tests. Raw value contains the following data: Bytes 0-1: Last test result as microseconds to discharge cap, saturates at max value. Test result expected in range 25 \u003c= result \u003c= 5000000, lower indicates specific error code. Bytes 2-3: Minutes since last test, saturates at max value.Bytes 4-5: Lifetime number of tests, not incremented on power cycle, saturates at max value. Normalized value is set to one on test failure or 11 if the capacitor has been tested in an excessive temperature condition, otherwise 100.", "display_type": "normalized" }, "176": { + "display_name": "Erase Fail Count", "ideal": "", "critical": false, "description": "S.M.A.R.T. parameter indicates a number of flash erase command failures.", "display_type": "normalized" }, "177": { + "display_name": "Wear Range Delta", "ideal": "", "critical": false, "description": "Delta between most-worn and least-worn Flash blocks. It describes how good/bad the wearleveling of the SSD works on a more technical way. ", "display_type": "normalized" }, "179": { + "display_name": "Used Reserved Block Count Total", "ideal": "", "critical": false, "description": "Pre-Fail attribute used at least in Samsung devices.", "display_type": "normalized" }, "180": { + "display_name": "Unused Reserved Block Count Total", "ideal": "", "critical": false, "description": "\"Pre-Fail\" attribute used at least in HP devices. ", "display_type": "normalized" }, "181": { + "display_name": "Program Fail Count Total", "ideal": "", "critical": false, "description": "Total number of Flash program operation failures since the drive was deployed.", "display_type": "normalized" }, "182": { + "display_name": "Erase Fail Count", "ideal": "", "critical": false, "description": "\"Pre-Fail\" Attribute used at least in Samsung devices.", "display_type": "normalized" }, "183": { + "display_name": "SATA Downshift Error Count or Runtime Bad Block", "ideal": "low", "critical": false, "description": "Western Digital, Samsung or Seagate attribute: Either the number of downshifts of link speed (e.g. from 6Gbit/s to 3Gbit/s) or the total number of data blocks with detected, uncorrectable errors encountered during normal operation. Although degradation of this parameter can be an indicator of drive aging and/or potential electromechanical problems, it does not directly indicate imminent drive failure.", @@ -702,6 +538,7 @@ export const sdc = { "display_type": "raw" }, "184": { + "display_name": "End-to-End error", "ideal": "low", "critical": true, "description": "This attribute is a part of Hewlett-Packard\"s SMART IV technology, as well as part of other vendors\" IO Error Detection and Correction schemas, and it contains a count of parity errors which occur in the data path to the media via the drive\"s cache RAM", @@ -749,18 +586,21 @@ export const sdc = { "display_type": "normalized" }, "185": { + "display_name": "Head Stability", "ideal": "", "critical": false, "description": "Western Digital attribute.", "display_type": "normalized" }, "186": { + "display_name": "Induced Op-Vibration Detection", "ideal": "", "critical": false, "description": "Western Digital attribute.", "display_type": "normalized" }, "187": { + "display_name": "Reported Uncorrectable Errors", "ideal": "low", "critical": true, "description": "The count of errors that could not be recovered using hardware ECC (see attribute 195).", @@ -813,6 +653,7 @@ export const sdc = { "display_type": "raw" }, "188": { + "display_name": "Command Timeout", "ideal": "low", "critical": true, "description": "The count of aborted operations due to HDD timeout. Normally this attribute value should be equal to zero.", @@ -865,6 +706,7 @@ export const sdc = { "display_type": "raw" }, "189": { + "display_name": "High Fly Writes", "ideal": "low", "critical": false, "description": "HDD manufacturers implement a flying height sensor that attempts to provide additional protections for write operations by detecting when a recording head is flying outside its normal operating range. If an unsafe fly height condition is encountered, the write process is stopped, and the information is rewritten or reallocated to a safe region of the hard drive. This attribute indicates the count of these errors detected over the lifetime of the drive.", @@ -912,18 +754,21 @@ export const sdc = { "display_type": "raw" }, "190": { + "display_name": "Temperature Difference", "ideal": "", "critical": false, "description": "Value is equal to (100-temp. °C), allowing manufacturer to set a minimum threshold which corresponds to a maximum temperature. This also follows the convention of 100 being a best-case value and lower values being undesirable. However, some older drives may instead report raw Temperature (identical to 0xC2) or Temperature minus 50 here.", "display_type": "normalized" }, "191": { + "display_name": "G-sense Error Rate", "ideal": "low", "critical": false, "description": "The count of errors resulting from externally induced shock and vibration. ", "display_type": "normalized" }, "192": { + "display_name": "Power-off Retract Count", "ideal": "low", "critical": false, "description": "Number of power-off or emergency retract cycles.", @@ -971,12 +816,14 @@ export const sdc = { "display_type": "raw" }, "193": { + "display_name": "Load Cycle Count", "ideal": "low", "critical": false, "description": "Count of load/unload cycles into head landing zone position.[45] Some drives use 225 (0xE1) for Load Cycle Count instead.", "display_type": "normalized" }, "194": { + "display_name": "Temperature", "ideal": "low", "critical": false, "description": "Indicates the device temperature, if the appropriate sensor is fitted. Lowest byte of the raw value contains the exact temperature value (Celsius degrees).", @@ -984,6 +831,7 @@ export const sdc = { "display_type": "transformed" }, "195": { + "display_name": "Hardware ECC Recovered", "ideal": "", "critical": false, "description": "(Vendor-specific raw value.) The raw value has different structure for different vendors and is often not meaningful as a decimal number.", @@ -1031,6 +879,7 @@ export const sdc = { "display_type": "normalized" }, "196": { + "display_name": "Reallocation Event Count", "ideal": "low", "critical": true, "description": "Count of remap operations. The raw value of this attribute shows the total count of attempts to transfer data from reallocated sectors to a spare area. Both successful and unsuccessful attempts are counted.", @@ -1083,6 +932,7 @@ export const sdc = { "display_type": "raw" }, "197": { + "display_name": "Current Pending Sector Count", "ideal": "low", "critical": true, "description": "Count of \"unstable\" sectors (waiting to be remapped, because of unrecoverable read errors). If an unstable sector is subsequently read successfully, the sector is remapped and this value is decreased. Read errors on a sector will not remap the sector immediately (since the correct value cannot be read and so the value to remap is not known, and also it might become readable later); instead, the drive firmware remembers that the sector needs to be remapped, and will remap it the next time it\"s written.", @@ -1135,6 +985,7 @@ export const sdc = { "display_type": "raw" }, "198": { + "display_name": "(Offline) Uncorrectable Sector Count", "ideal": "low", "critical": true, "description": "The total count of uncorrectable errors when reading/writing a sector. A rise in the value of this attribute indicates defects of the disk surface and/or problems in the mechanical subsystem.", @@ -1187,6 +1038,7 @@ export const sdc = { "display_type": "raw" }, "199": { + "display_name": "UltraDMA CRC Error Count", "ideal": "low", "critical": false, "description": "The count of errors in data transfer via the interface cable as determined by ICRC (Interface Cyclic Redundancy Check).", @@ -1239,246 +1091,287 @@ export const sdc = { "display_type": "raw" }, "2": { + "display_name": "Throughput Performance", "ideal": "high", "critical": false, "description": "Overall (general) throughput performance of a hard disk drive. If the value of this attribute is decreasing there is a high probability that there is a problem with the disk.", "display_type": "normalized" }, "200": { + "display_name": "Multi-Zone Error Rate", "ideal": "low", "critical": false, "description": "The count of errors found when writing a sector. The higher the value, the worse the disk\"s mechanical condition is.", "display_type": "normalized" }, "201": { + "display_name": "Soft Read Error Rate", "ideal": "low", "critical": true, "description": "Count indicates the number of uncorrectable software read errors.", "display_type": "normalized" }, "202": { + "display_name": "Data Address Mark errors", "ideal": "low", "critical": false, "description": "Count of Data Address Mark errors (or vendor-specific).", "display_type": "normalized" }, "203": { + "display_name": "Run Out Cancel", "ideal": "low", "critical": false, "description": "The number of errors caused by incorrect checksum during the error correction.", "display_type": "normalized" }, "204": { + "display_name": "Soft ECC Correction", "ideal": "low", "critical": false, "description": "Count of errors corrected by the internal error correction software.", "display_type": "" }, "205": { + "display_name": "Thermal Asperity Rate", "ideal": "low", "critical": false, "description": "Count of errors due to high temperature.", "display_type": "normalized" }, "206": { + "display_name": "Flying Height", "ideal": "", "critical": false, "description": "Height of heads above the disk surface. If too low, head crash is more likely; if too high, read/write errors are more likely.", "display_type": "normalized" }, "207": { + "display_name": "Spin High Current", "ideal": "low", "critical": false, "description": "Amount of surge current used to spin up the drive.", "display_type": "normalized" }, "208": { + "display_name": "Spin Buzz", "ideal": "", "critical": false, "description": "Count of buzz routines needed to spin up the drive due to insufficient power.", "display_type": "normalized" }, "209": { + "display_name": "Offline Seek Performance", "ideal": "", "critical": false, "description": "Drive\"s seek performance during its internal tests.", "display_type": "normalized" }, "210": { + "display_name": "Vibration During Write", "ideal": "", "critical": false, "description": "Found in Maxtor 6B200M0 200GB and Maxtor 2R015H1 15GB disks.", "display_type": "normalized" }, "211": { + "display_name": "Vibration During Write", "ideal": "", "critical": false, "description": "A recording of a vibration encountered during write operations.", "display_type": "normalized" }, "212": { + "display_name": "Shock During Write", "ideal": "", "critical": false, "description": "A recording of shock encountered during write operations.", "display_type": "normalized" }, "22": { + "display_name": "Current Helium Level", "ideal": "high", "critical": false, "description": "Specific to He8 drives from HGST. This value measures the helium inside of the drive specific to this manufacturer. It is a pre-fail attribute that trips once the drive detects that the internal environment is out of specification.", "display_type": "normalized" }, "220": { + "display_name": "Disk Shift", "ideal": "low", "critical": false, "description": "Distance the disk has shifted relative to the spindle (usually due to shock or temperature). Unit of measure is unknown.", "display_type": "normalized" }, "221": { + "display_name": "G-Sense Error Rate", "ideal": "low", "critical": false, "description": "The count of errors resulting from externally induced shock and vibration.", "display_type": "normalized" }, "222": { + "display_name": "Loaded Hours", "ideal": "", "critical": false, "description": "Time spent operating under data load (movement of magnetic head armature).", "display_type": "normalized" }, "223": { + "display_name": "Load/Unload Retry Count", "ideal": "", "critical": false, "description": "Count of times head changes position.", "display_type": "normalized" }, "224": { + "display_name": "Load Friction", "ideal": "low", "critical": false, "description": "Resistance caused by friction in mechanical parts while operating.", "display_type": "normalized" }, "225": { + "display_name": "Load/Unload Cycle Count", "ideal": "low", "critical": false, "description": "Total count of load cycles Some drives use 193 (0xC1) for Load Cycle Count instead. See Description for 193 for significance of this number. ", "display_type": "normalized" }, "226": { + "display_name": "Load \"In\"-time", "ideal": "", "critical": false, "description": "Total time of loading on the magnetic heads actuator (time not spent in parking area).", "display_type": "normalized" }, "227": { + "display_name": "Torque Amplification Count", "ideal": "low", "critical": false, "description": "Count of attempts to compensate for platter speed variations.[66]", "display_type": "" }, "228": { + "display_name": "Power-Off Retract Cycle", "ideal": "low", "critical": false, "description": "The number of power-off cycles which are counted whenever there is a \"retract event\" and the heads are loaded off of the media such as when the machine is powered down, put to sleep, or is idle.", "display_type": "" }, "230": { + "display_name": "GMR Head Amplitude ", "ideal": "", "critical": false, "description": "Amplitude of \"thrashing\" (repetitive head moving motions between operations).", "display_type": "normalized" }, "231": { + "display_name": "Life Left", "ideal": "", "critical": false, "description": "Indicates the approximate SSD life left, in terms of program/erase cycles or available reserved blocks. A normalized value of 100 represents a new drive, with a threshold value at 10 indicating a need for replacement. A value of 0 may mean that the drive is operating in read-only mode to allow data recovery.", "display_type": "normalized" }, "232": { + "display_name": "Endurance Remaining", "ideal": "", "critical": false, "description": "Number of physical erase cycles completed on the SSD as a percentage of the maximum physical erase cycles the drive is designed to endure.", "display_type": "normalized" }, "233": { + "display_name": "Media Wearout Indicator", "ideal": "", "critical": false, "description": "Intel SSDs report a normalized value from 100, a new drive, to a minimum of 1. It decreases while the NAND erase cycles increase from 0 to the maximum-rated cycles.", "display_type": "normalized" }, "234": { + "display_name": "Average erase count", "ideal": "", "critical": false, "description": "Decoded as: byte 0-1-2 = average erase count (big endian) and byte 3-4-5 = max erase count (big endian).", "display_type": "normalized" }, "235": { + "display_name": "Good Block Count", "ideal": "", "critical": false, "description": "Decoded as: byte 0-1-2 = good block count (big endian) and byte 3-4 = system (free) block count.", "display_type": "normalized" }, "240": { + "display_name": "Head Flying Hours", "ideal": "", "critical": false, "description": "Time spent during the positioning of the drive heads.[15][71] Some Fujitsu drives report the count of link resets during a data transfer.", "display_type": "normalized" }, "241": { + "display_name": "Total LBAs Written", "ideal": "", "critical": false, "description": "Total count of LBAs written.", "display_type": "normalized" }, "242": { + "display_name": "Total LBAs Read", "ideal": "", "critical": false, "description": "Total count of LBAs read.Some S.M.A.R.T. utilities will report a negative number for the raw value since in reality it has 48 bits rather than 32.", "display_type": "normalized" }, "243": { + "display_name": "Total LBAs Written Expanded", "ideal": "", "critical": false, "description": "The upper 5 bytes of the 12-byte total number of LBAs written to the device. The lower 7 byte value is located at attribute 0xF1.", "display_type": "normalized" }, "244": { + "display_name": "Total LBAs Read Expanded", "ideal": "", "critical": false, "description": "The upper 5 bytes of the 12-byte total number of LBAs read from the device. The lower 7 byte value is located at attribute 0xF2.", "display_type": "normalized" }, "249": { + "display_name": "NAND Writes (1GiB)", "ideal": "", "critical": false, "description": "Total NAND Writes. Raw value reports the number of writes to NAND in 1 GB increments.", "display_type": "normalized" }, "250": { + "display_name": "Read Error Retry Rate", "ideal": "low", "critical": false, "description": "Count of errors while reading from a disk.", "display_type": "normalized" }, "251": { + "display_name": "Minimum Spares Remaining", "ideal": "", "critical": false, "description": "The Minimum Spares Remaining attribute indicates the number of remaining spare blocks as a percentage of the total number of spare blocks available.", "display_type": "normalized" }, "252": { + "display_name": "Newly Added Bad Flash Block", "ideal": "", "critical": false, "description": "The Newly Added Bad Flash Block attribute indicates the total number of bad flash blocks the drive detected since it was first initialized in manufacturing.", "display_type": "normalized" }, "254": { + "display_name": "Free Fall Protection", "ideal": "low", "critical": false, "description": "Count of \"Free Fall Events\" detected.", "display_type": "normalized" }, "3": { + "display_name": "Spin-Up Time", "ideal": "low", "critical": false, "description": "Average time of spindle spin up (from zero RPM to fully operational [milliseconds]).", @@ -1526,6 +1419,7 @@ export const sdc = { "display_type": "normalized" }, "4": { + "display_name": "Start/Stop Count", "ideal": "", "critical": false, "description": "A tally of spindle start/stop cycles. The spindle turns on, and hence the count is increased, both when the hard disk is turned on after having before been turned entirely off (disconnected from power source) and when the hard disk returns from having previously been put to sleep mode.", @@ -1573,6 +1467,7 @@ export const sdc = { "display_type": "raw" }, "5": { + "display_name": "Reallocated Sectors Count", "ideal": "low", "critical": true, "description": "Count of reallocated sectors. The raw value represents a count of the bad sectors that have been found and remapped.Thus, the higher the attribute value, the more sectors the drive has had to reallocate. This value is primarily used as a metric of the life expectancy of the drive; a drive which has had any reallocations at all is significantly more likely to fail in the immediate months.", @@ -1625,12 +1520,14 @@ export const sdc = { "display_type": "raw" }, "6": { + "display_name": "Read Channel Margin", "ideal": "", "critical": false, "description": "Margin of a channel while reading data. The function of this attribute is not specified.", "display_type": "normalized" }, "7": { + "display_name": "Seek Error Rate", "ideal": "", "critical": false, "description": "(Vendor specific raw value.) Rate of seek errors of the magnetic heads. If there is a partial failure in the mechanical positioning system, then seek errors will arise. Such a failure may be due to numerous factors, such as damage to a servo, or thermal widening of the hard disk. The raw value has different structure for different vendors and is often not meaningful as a decimal number.", @@ -1678,12 +1575,14 @@ export const sdc = { "display_type": "normalized" }, "8": { + "display_name": "Seek Time Performance", "ideal": "high", "critical": false, "description": "Average performance of seek operations of the magnetic heads. If this attribute is decreasing, it is a sign of problems in the mechanical subsystem.", "display_type": "normalized" }, "9": { + "display_name": "Power-On Hours", "ideal": "", "critical": false, "description": "Count of hours in power-on state. The raw value of this attribute shows total count of hours (or minutes, or seconds, depending on manufacturer) in power-on state. By default, the total expected lifetime of a hard disk in perfect condition is defined as 5 years (running every day and night on all days). This is equal to 1825 days in 24/7 mode or 43800 hours. On some pre-2005 drives, this raw value may advance erratically and/or \"wrap around\" (reset to zero periodically).", diff --git a/webapp/frontend/src/app/data/mock/device/details/sdd.ts b/webapp/frontend/src/app/data/mock/device/details/sdd.ts index ccf09b0..3442593 100644 --- a/webapp/frontend/src/app/data/mock/device/details/sdd.ts +++ b/webapp/frontend/src/app/data/mock/device/details/sdd.ts @@ -2,7 +2,7 @@ export const sdd = { "data": { "device": { "CreatedAt": "2021-06-24T21:17:31.30374-07:00", - "UpdatedAt": "2021-06-26T14:26:20.902325-07:00", + "UpdatedAt": "2021-10-24T16:37:57.013758-07:00", "DeletedAt": null, "wwn": "0x5000cca252c859cc", "device_name": "sdd", @@ -23,7 +23,7 @@ export const sdd = { "device_status": 0 }, "smart_results": [{ - "date": "2020-08-21T22:27:02Z", + "date": "2021-10-24T23:20:44Z", "device_wwn": "0x5000cca252c859cc", "device_protocol": "SCSI", "temp": 34, @@ -32,272 +32,186 @@ export const sdd = { "attrs": { "read_correction_algorithm_invocations": { "attribute_id": "read_correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", "value": 0, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "read_errors_corrected_by_eccdelayed": { "attribute_id": "read_errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", "value": 0, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "read_errors_corrected_by_eccfast": { "attribute_id": "read_errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", "value": 300357663, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "read_errors_corrected_by_rereads_rewrites": { "attribute_id": "read_errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", "value": 0, "thresh": 0, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "read_total_errors_corrected": { "attribute_id": "read_total_errors_corrected", - "name": "Read Total Errors Corrected", "value": 300357663, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "read_total_uncorrected_errors": { "attribute_id": "read_total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", "value": 0, "thresh": 0, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "scsi_grown_defect_list": { "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", "value": 56, "thresh": 0, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "write_correction_algorithm_invocations": { "attribute_id": "write_correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", "value": 0, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "write_errors_corrected_by_eccdelayed": { "attribute_id": "write_errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", "value": 0, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "write_errors_corrected_by_eccfast": { "attribute_id": "write_errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", "value": 0, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "write_errors_corrected_by_rereads_rewrites": { "attribute_id": "write_errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", "value": 0, "thresh": 0, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "write_total_errors_corrected": { "attribute_id": "write_total_errors_corrected", - "name": "Write Total Errors Corrected", "value": 0, "thresh": -1, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 }, "write_total_uncorrected_errors": { "attribute_id": "write_total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", "value": 0, "thresh": 0, - "transformed_value": 0 + "transformed_value": 0, + "status": 0 } - } - },{ - "date": "2020-08-21T22:27:02Z", - "device_wwn": "0x5000cca252c859cc", - "device_protocol": "SCSI", - "temp": 34, - "power_on_hours": 43549, - "power_cycle_count": 0, - "attrs": { - "read_correction_algorithm_invocations": { - "attribute_id": "read_correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": -1, - "transformed_value": 0 - }, - "read_errors_corrected_by_eccdelayed": { - "attribute_id": "read_errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": -1, - "transformed_value": 0 - }, - "read_errors_corrected_by_eccfast": { - "attribute_id": "read_errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 300357663, - "thresh": -1, - "transformed_value": 0 - }, - "read_errors_corrected_by_rereads_rewrites": { - "attribute_id": "read_errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, - "read_total_errors_corrected": { - "attribute_id": "read_total_errors_corrected", - "name": "Read Total Errors Corrected", - "value": 300357663, - "thresh": -1, - "transformed_value": 0 - }, - "read_total_uncorrected_errors": { - "attribute_id": "read_total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, - "scsi_grown_defect_list": { - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 56, - "thresh": 0, - "transformed_value": 0 - }, - "write_correction_algorithm_invocations": { - "attribute_id": "write_correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": -1, - "transformed_value": 0 - }, - "write_errors_corrected_by_eccdelayed": { - "attribute_id": "write_errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, - "thresh": -1, - "transformed_value": 0 - }, - "write_errors_corrected_by_eccfast": { - "attribute_id": "write_errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": -1, - "transformed_value": 0 - }, - "write_errors_corrected_by_rereads_rewrites": { - "attribute_id": "write_errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, - "write_total_errors_corrected": { - "attribute_id": "write_total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": -1, - "transformed_value": 0 - }, - "write_total_uncorrected_errors": { - "attribute_id": "write_total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - } - } + }, + "Status": 0 }] }, "metadata": { "read_correction_algorithm_invocations": { + "display_name": "Read Correction Algorithm Invocations", "ideal": "", "critical": false, "description": "", "display_type": "" }, "read_errors_corrected_by_eccdelayed": { + "display_name": "Read Errors Corrected by ECC Delayed", "ideal": "", "critical": false, "description": "", "display_type": "" }, "read_errors_corrected_by_eccfast": { + "display_name": "Read Errors Corrected by ECC Fast", "ideal": "", "critical": false, "description": "", "display_type": "" }, "read_errors_corrected_by_rereads_rewrites": { + "display_name": "Read Errors Corrected by ReReads/ReWrites", "ideal": "low", "critical": true, "description": "", "display_type": "" }, "read_total_errors_corrected": { + "display_name": "Read Total Errors Corrected", "ideal": "", "critical": false, "description": "", "display_type": "" }, "read_total_uncorrected_errors": { + "display_name": "Read Total Uncorrected Errors", "ideal": "low", "critical": true, "description": "", "display_type": "" }, "scsi_grown_defect_list": { + "display_name": "Grown Defect List", "ideal": "low", "critical": true, "description": "", "display_type": "" }, "write_correction_algorithm_invocations": { + "display_name": "Write Correction Algorithm Invocations", "ideal": "", "critical": false, "description": "", "display_type": "" }, "write_errors_corrected_by_eccdelayed": { + "display_name": "Write Errors Corrected by ECC Delayed", "ideal": "", "critical": false, "description": "", "display_type": "" }, "write_errors_corrected_by_eccfast": { + "display_name": "Write Errors Corrected by ECC Fast", "ideal": "", "critical": false, "description": "", "display_type": "" }, "write_errors_corrected_by_rereads_rewrites": { + "display_name": "Write Errors Corrected by ReReads/ReWrites", "ideal": "low", "critical": true, "description": "", "display_type": "" }, "write_total_errors_corrected": { + "display_name": "Write Total Errors Corrected", "ideal": "", "critical": false, "description": "", "display_type": "" }, "write_total_uncorrected_errors": { + "display_name": "Write Total Uncorrected Errors", "ideal": "low", "critical": true, "description": "", diff --git a/webapp/frontend/src/app/data/mock/device/details/sde.ts b/webapp/frontend/src/app/data/mock/device/details/sde.ts index 4e08e00..42c5f1a 100644 --- a/webapp/frontend/src/app/data/mock/device/details/sde.ts +++ b/webapp/frontend/src/app/data/mock/device/details/sde.ts @@ -1,1242 +1,222 @@ export const sde = { "data": { "device": { - "CreatedAt": "2020-08-28T07:55:27.768220079Z", - "UpdatedAt": "2020-09-08T21:39:26.578973-07:00", + "CreatedAt": "2021-06-24T21:17:31.304461-07:00", + "UpdatedAt": "2021-10-24T16:40:16.495248-07:00", "DeletedAt": null, "wwn": "0x5000cca264ebc248", "device_name": "sde", - "manufacturer": "SEAGATE", + "manufacturer": "ATA", "model_name": "WDC_WD140EDFZ-11A0VA0", "interface_type": "SCSI", "interface_speed": "", "serial_number": "9RK3XXXXX", "firmware": "", - "rotational_speed": 10500, - "capacity": 1200243695616, - "form_factor": "2.5 inches", + "rotational_speed": 0, + "capacity": 14000519643136, + "form_factor": "", "smart_support": false, "device_protocol": "SCSI", - "device_type": "scsi", + "device_type": "", + "label": "", + "host_id": "", + "device_status": 0 }, "smart_results": [{ - "ID": 48, - "CreatedAt": "2020-09-08T21:39:26.579623-07:00", - "UpdatedAt": "2020-09-08T21:39:26.579623-07:00", - "DeletedAt": null, + "date": "2021-10-24T23:20:44Z", "device_wwn": "0x5000cca264ebc248", - "date": "2018-12-16T15:09:15-08:00", - "smart_status": "passed", + "device_protocol": "SCSI", "temp": 31, "power_on_hours": 5675, "power_cycle_count": 0, - "ata_attributes": [], - "nvme_attributes": [], - "scsi_attributes": [{ - "ID": 196, - "CreatedAt": "2020-09-08T21:39:26.57989-07:00", - "UpdatedAt": "2020-09-08T21:39:26.57989-07:00", - "DeletedAt": null, - "smart_id": 48, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 0, - "thresh": 0, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 170, - "CreatedAt": "2020-09-07T15:47:21.347996632Z", - "UpdatedAt": "2020-09-07T15:47:21.347996632Z", - "DeletedAt": null, - "smart_id": 42, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 144, - "CreatedAt": "2020-09-07T15:38:56.643262186Z", - "UpdatedAt": "2020-09-07T15:38:56.643262186Z", - "DeletedAt": null, - "smart_id": 36, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 118, - "CreatedAt": "2020-09-07T15:26:07.517433189Z", - "UpdatedAt": "2020-09-07T15:26:07.517433189Z", - "DeletedAt": null, - "smart_id": 30, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 92, - "CreatedAt": "2020-09-07T15:19:17.478404748Z", - "UpdatedAt": "2020-09-07T15:19:17.478404748Z", - "DeletedAt": null, - "smart_id": 24, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 66, - "CreatedAt": "2020-09-07T15:10:40.257359179Z", - "UpdatedAt": "2020-09-07T15:10:40.257359179Z", - "DeletedAt": null, - "smart_id": 18, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 40, - "CreatedAt": "2020-09-06T23:14:39.858833764Z", - "UpdatedAt": "2020-09-06T23:14:39.858833764Z", - "DeletedAt": null, - "smart_id": 12, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 14, - "CreatedAt": "2020-08-28T07:55:27.880197174Z", - "UpdatedAt": "2020-08-28T07:55:27.880197174Z", - "DeletedAt": null, - "smart_id": 6, - "attribute_id": "scsi_grown_defect_list", - "name": "Grown Defect List", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 197, - "CreatedAt": "2020-09-08T21:39:26.580007-07:00", - "UpdatedAt": "2020-09-08T21:39:26.580007-07:00", - "DeletedAt": null, - "smart_id": 48, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 1410362924, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 171, - "CreatedAt": "2020-09-07T15:47:21.348133432Z", - "UpdatedAt": "2020-09-07T15:47:21.348133432Z", - "DeletedAt": null, - "smart_id": 42, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 1410362924, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 145, - "CreatedAt": "2020-09-07T15:38:56.643384087Z", - "UpdatedAt": "2020-09-07T15:38:56.643384087Z", - "DeletedAt": null, - "smart_id": 36, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 1410362924, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 119, - "CreatedAt": "2020-09-07T15:26:07.517563293Z", - "UpdatedAt": "2020-09-07T15:26:07.517563293Z", - "DeletedAt": null, - "smart_id": 30, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 1410362924, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 93, - "CreatedAt": "2020-09-07T15:19:17.478524847Z", - "UpdatedAt": "2020-09-07T15:19:17.478524847Z", - "DeletedAt": null, - "smart_id": 24, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 1410362924, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 67, - "CreatedAt": "2020-09-07T15:10:40.25748088Z", - "UpdatedAt": "2020-09-07T15:10:40.25748088Z", - "DeletedAt": null, - "smart_id": 18, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 1410362924, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 41, - "CreatedAt": "2020-09-06T23:14:39.858944067Z", - "UpdatedAt": "2020-09-06T23:14:39.858944067Z", - "DeletedAt": null, - "smart_id": 12, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 1410362924, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 15, - "CreatedAt": "2020-08-28T07:55:27.880309617Z", - "UpdatedAt": "2020-08-28T07:55:27.880309617Z", - "DeletedAt": null, - "smart_id": 6, - "attribute_id": "read.errors_corrected_by_eccfast", - "name": "Read Errors Corrected by ECC Fast", - "value": 1410362924, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 198, - "CreatedAt": "2020-09-08T21:39:26.580075-07:00", - "UpdatedAt": "2020-09-08T21:39:26.580075-07:00", - "DeletedAt": null, - "smart_id": 48, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 172, - "CreatedAt": "2020-09-07T15:47:21.348217832Z", - "UpdatedAt": "2020-09-07T15:47:21.348217832Z", - "DeletedAt": null, - "smart_id": 42, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 146, - "CreatedAt": "2020-09-07T15:38:56.643456487Z", - "UpdatedAt": "2020-09-07T15:38:56.643456487Z", - "DeletedAt": null, - "smart_id": 36, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 120, - "CreatedAt": "2020-09-07T15:26:07.517650595Z", - "UpdatedAt": "2020-09-07T15:26:07.517650595Z", - "DeletedAt": null, - "smart_id": 30, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 94, - "CreatedAt": "2020-09-07T15:19:17.478603147Z", - "UpdatedAt": "2020-09-07T15:19:17.478603147Z", - "DeletedAt": null, - "smart_id": 24, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 68, - "CreatedAt": "2020-09-07T15:10:40.257557681Z", - "UpdatedAt": "2020-09-07T15:10:40.257557681Z", - "DeletedAt": null, - "smart_id": 18, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 42, - "CreatedAt": "2020-09-06T23:14:39.859017069Z", - "UpdatedAt": "2020-09-06T23:14:39.859017069Z", - "DeletedAt": null, - "smart_id": 12, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 16, - "CreatedAt": "2020-08-28T07:55:27.880411683Z", - "UpdatedAt": "2020-08-28T07:55:27.880411683Z", - "DeletedAt": null, - "smart_id": 6, - "attribute_id": "read.errors_corrected_by_eccdelayed", - "name": "Read Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 199, - "CreatedAt": "2020-09-08T21:39:26.580136-07:00", - "UpdatedAt": "2020-09-08T21:39:26.580136-07:00", - "DeletedAt": null, - "smart_id": 48, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 173, - "CreatedAt": "2020-09-07T15:47:21.348293632Z", - "UpdatedAt": "2020-09-07T15:47:21.348293632Z", - "DeletedAt": null, - "smart_id": 42, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 147, - "CreatedAt": "2020-09-07T15:38:56.643525088Z", - "UpdatedAt": "2020-09-07T15:38:56.643525088Z", - "DeletedAt": null, - "smart_id": 36, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 121, - "CreatedAt": "2020-09-07T15:26:07.517759798Z", - "UpdatedAt": "2020-09-07T15:26:07.517759798Z", - "DeletedAt": null, - "smart_id": 30, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 95, - "CreatedAt": "2020-09-07T15:19:17.478705847Z", - "UpdatedAt": "2020-09-07T15:19:17.478705847Z", - "DeletedAt": null, - "smart_id": 24, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 69, - "CreatedAt": "2020-09-07T15:10:40.257628781Z", - "UpdatedAt": "2020-09-07T15:10:40.257628781Z", - "DeletedAt": null, - "smart_id": 18, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 43, - "CreatedAt": "2020-09-06T23:14:39.859087271Z", - "UpdatedAt": "2020-09-06T23:14:39.859087271Z", - "DeletedAt": null, - "smart_id": 12, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 17, - "CreatedAt": "2020-08-28T07:55:27.880496133Z", - "UpdatedAt": "2020-08-28T07:55:27.880496133Z", - "DeletedAt": null, - "smart_id": 6, - "attribute_id": "read.errors_corrected_by_rereads_rewrites", - "name": "Read Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 200, - "CreatedAt": "2020-09-08T21:39:26.580199-07:00", - "UpdatedAt": "2020-09-08T21:39:26.580199-07:00", - "DeletedAt": null, - "smart_id": 48, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", - "value": 1410362924, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 174, - "CreatedAt": "2020-09-07T15:47:21.348561033Z", - "UpdatedAt": "2020-09-07T15:47:21.348561033Z", - "DeletedAt": null, - "smart_id": 42, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", + "attrs": { + "read_correction_algorithm_invocations": { + "attribute_id": "read_correction_algorithm_invocations", + "value": 0, + "thresh": -1, + "transformed_value": 0, + "status": 0 + }, + "read_errors_corrected_by_eccdelayed": { + "attribute_id": "read_errors_corrected_by_eccdelayed", + "value": 0, + "thresh": -1, + "transformed_value": 0, + "status": 0 + }, + "read_errors_corrected_by_eccfast": { + "attribute_id": "read_errors_corrected_by_eccfast", "value": 1410362924, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 148, - "CreatedAt": "2020-09-07T15:38:56.643590489Z", - "UpdatedAt": "2020-09-07T15:38:56.643590489Z", - "DeletedAt": null, - "smart_id": 36, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", + "thresh": -1, + "transformed_value": 0, + "status": 0 + }, + "read_errors_corrected_by_rereads_rewrites": { + "attribute_id": "read_errors_corrected_by_rereads_rewrites", + "value": 0, + "thresh": 0, + "transformed_value": 0, + "status": 0 + }, + "read_total_errors_corrected": { + "attribute_id": "read_total_errors_corrected", "value": 1410362924, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 122, - "CreatedAt": "2020-09-07T15:26:07.5178383Z", - "UpdatedAt": "2020-09-07T15:26:07.5178383Z", - "DeletedAt": null, - "smart_id": 30, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", - "value": 1410362924, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 96, - "CreatedAt": "2020-09-07T15:19:17.478776947Z", - "UpdatedAt": "2020-09-07T15:19:17.478776947Z", - "DeletedAt": null, - "smart_id": 24, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", - "value": 1410362924, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 70, - "CreatedAt": "2020-09-07T15:10:40.257696282Z", - "UpdatedAt": "2020-09-07T15:10:40.257696282Z", - "DeletedAt": null, - "smart_id": 18, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", - "value": 1410362924, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 44, - "CreatedAt": "2020-09-06T23:14:39.859153473Z", - "UpdatedAt": "2020-09-06T23:14:39.859153473Z", - "DeletedAt": null, - "smart_id": 12, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", - "value": 1410362924, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 18, - "CreatedAt": "2020-08-28T07:55:27.8805957Z", - "UpdatedAt": "2020-08-28T07:55:27.8805957Z", - "DeletedAt": null, - "smart_id": 6, - "attribute_id": "read.total_errors_corrected", - "name": "Read Total Errors Corrected", - "value": 1410362924, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 201, - "CreatedAt": "2020-09-08T21:39:26.580259-07:00", - "UpdatedAt": "2020-09-08T21:39:26.580259-07:00", - "DeletedAt": null, - "smart_id": 48, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 175, - "CreatedAt": "2020-09-07T15:47:21.348729333Z", - "UpdatedAt": "2020-09-07T15:47:21.348729333Z", - "DeletedAt": null, - "smart_id": 42, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 149, - "CreatedAt": "2020-09-07T15:38:56.643654789Z", - "UpdatedAt": "2020-09-07T15:38:56.643654789Z", - "DeletedAt": null, - "smart_id": 36, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 123, - "CreatedAt": "2020-09-07T15:26:07.517916302Z", - "UpdatedAt": "2020-09-07T15:26:07.517916302Z", - "DeletedAt": null, - "smart_id": 30, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 97, - "CreatedAt": "2020-09-07T15:19:17.478847046Z", - "UpdatedAt": "2020-09-07T15:19:17.478847046Z", - "DeletedAt": null, - "smart_id": 24, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 71, - "CreatedAt": "2020-09-07T15:10:40.257761682Z", - "UpdatedAt": "2020-09-07T15:10:40.257761682Z", - "DeletedAt": null, - "smart_id": 18, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 45, - "CreatedAt": "2020-09-06T23:14:39.859216975Z", - "UpdatedAt": "2020-09-06T23:14:39.859216975Z", - "DeletedAt": null, - "smart_id": 12, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 19, - "CreatedAt": "2020-08-28T07:55:27.880669044Z", - "UpdatedAt": "2020-08-28T07:55:27.880669044Z", - "DeletedAt": null, - "smart_id": 6, - "attribute_id": "read.correction_algorithm_invocations", - "name": "Read Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 202, - "CreatedAt": "2020-09-08T21:39:26.580325-07:00", - "UpdatedAt": "2020-09-08T21:39:26.580325-07:00", - "DeletedAt": null, - "smart_id": 48, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 176, - "CreatedAt": "2020-09-07T15:47:21.348844733Z", - "UpdatedAt": "2020-09-07T15:47:21.348844733Z", - "DeletedAt": null, - "smart_id": 42, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 150, - "CreatedAt": "2020-09-07T15:38:56.64372119Z", - "UpdatedAt": "2020-09-07T15:38:56.64372119Z", - "DeletedAt": null, - "smart_id": 36, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 124, - "CreatedAt": "2020-09-07T15:26:07.517990504Z", - "UpdatedAt": "2020-09-07T15:26:07.517990504Z", - "DeletedAt": null, - "smart_id": 30, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 98, - "CreatedAt": "2020-09-07T15:19:17.478914046Z", - "UpdatedAt": "2020-09-07T15:19:17.478914046Z", - "DeletedAt": null, - "smart_id": 24, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 72, - "CreatedAt": "2020-09-07T15:10:40.257850983Z", - "UpdatedAt": "2020-09-07T15:10:40.257850983Z", - "DeletedAt": null, - "smart_id": 18, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 46, - "CreatedAt": "2020-09-06T23:14:39.859281377Z", - "UpdatedAt": "2020-09-06T23:14:39.859281377Z", - "DeletedAt": null, - "smart_id": 12, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 20, - "CreatedAt": "2020-08-28T07:55:27.880762037Z", - "UpdatedAt": "2020-08-28T07:55:27.880762037Z", - "DeletedAt": null, - "smart_id": 6, - "attribute_id": "read.total_uncorrected_errors", - "name": "Read Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 203, - "CreatedAt": "2020-09-08T21:39:26.580401-07:00", - "UpdatedAt": "2020-09-08T21:39:26.580401-07:00", - "DeletedAt": null, - "smart_id": 48, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 177, - "CreatedAt": "2020-09-07T15:47:21.348954434Z", - "UpdatedAt": "2020-09-07T15:47:21.348954434Z", - "DeletedAt": null, - "smart_id": 42, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 151, - "CreatedAt": "2020-09-07T15:38:56.64378519Z", - "UpdatedAt": "2020-09-07T15:38:56.64378519Z", - "DeletedAt": null, - "smart_id": 36, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 125, - "CreatedAt": "2020-09-07T15:26:07.518063306Z", - "UpdatedAt": "2020-09-07T15:26:07.518063306Z", - "DeletedAt": null, - "smart_id": 30, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 99, - "CreatedAt": "2020-09-07T15:19:17.478978246Z", - "UpdatedAt": "2020-09-07T15:19:17.478978246Z", - "DeletedAt": null, - "smart_id": 24, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 73, - "CreatedAt": "2020-09-07T15:10:40.257919784Z", - "UpdatedAt": "2020-09-07T15:10:40.257919784Z", - "DeletedAt": null, - "smart_id": 18, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 47, - "CreatedAt": "2020-09-06T23:14:39.859343279Z", - "UpdatedAt": "2020-09-06T23:14:39.859343279Z", - "DeletedAt": null, - "smart_id": 12, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 21, - "CreatedAt": "2020-08-28T07:55:27.880831527Z", - "UpdatedAt": "2020-08-28T07:55:27.880831527Z", - "DeletedAt": null, - "smart_id": 6, - "attribute_id": "write.errors_corrected_by_eccfast", - "name": "Write Errors Corrected by ECC Fast", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 204, - "CreatedAt": "2020-09-08T21:39:26.580463-07:00", - "UpdatedAt": "2020-09-08T21:39:26.580463-07:00", - "DeletedAt": null, - "smart_id": 48, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 178, - "CreatedAt": "2020-09-07T15:47:21.349067634Z", - "UpdatedAt": "2020-09-07T15:47:21.349067634Z", - "DeletedAt": null, - "smart_id": 42, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 152, - "CreatedAt": "2020-09-07T15:38:56.643850091Z", - "UpdatedAt": "2020-09-07T15:38:56.643850091Z", - "DeletedAt": null, - "smart_id": 36, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 126, - "CreatedAt": "2020-09-07T15:26:07.518138308Z", - "UpdatedAt": "2020-09-07T15:26:07.518138308Z", - "DeletedAt": null, - "smart_id": 30, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 100, - "CreatedAt": "2020-09-07T15:19:17.479060646Z", - "UpdatedAt": "2020-09-07T15:19:17.479060646Z", - "DeletedAt": null, - "smart_id": 24, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 74, - "CreatedAt": "2020-09-07T15:10:40.257991684Z", - "UpdatedAt": "2020-09-07T15:10:40.257991684Z", - "DeletedAt": null, - "smart_id": 18, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 48, - "CreatedAt": "2020-09-06T23:14:39.859415381Z", - "UpdatedAt": "2020-09-06T23:14:39.859415381Z", - "DeletedAt": null, - "smart_id": 12, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 22, - "CreatedAt": "2020-08-28T07:55:27.88091659Z", - "UpdatedAt": "2020-08-28T07:55:27.88091659Z", - "DeletedAt": null, - "smart_id": 6, - "attribute_id": "write.errors_corrected_by_eccdelayed", - "name": "Write Errors Corrected by ECC Delayed", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 205, - "CreatedAt": "2020-09-08T21:39:26.580519-07:00", - "UpdatedAt": "2020-09-08T21:39:26.580519-07:00", - "DeletedAt": null, - "smart_id": 48, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 179, - "CreatedAt": "2020-09-07T15:47:21.349173034Z", - "UpdatedAt": "2020-09-07T15:47:21.349173034Z", - "DeletedAt": null, - "smart_id": 42, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 153, - "CreatedAt": "2020-09-07T15:38:56.643916492Z", - "UpdatedAt": "2020-09-07T15:38:56.643916492Z", - "DeletedAt": null, - "smart_id": 36, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 127, - "CreatedAt": "2020-09-07T15:26:07.51821131Z", - "UpdatedAt": "2020-09-07T15:26:07.51821131Z", - "DeletedAt": null, - "smart_id": 30, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 101, - "CreatedAt": "2020-09-07T15:19:17.479156345Z", - "UpdatedAt": "2020-09-07T15:19:17.479156345Z", - "DeletedAt": null, - "smart_id": 24, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 75, - "CreatedAt": "2020-09-07T15:10:40.258061285Z", - "UpdatedAt": "2020-09-07T15:10:40.258061285Z", - "DeletedAt": null, - "smart_id": 18, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 49, - "CreatedAt": "2020-09-06T23:14:39.859474183Z", - "UpdatedAt": "2020-09-06T23:14:39.859474183Z", - "DeletedAt": null, - "smart_id": 12, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 23, - "CreatedAt": "2020-08-28T07:55:27.880989189Z", - "UpdatedAt": "2020-08-28T07:55:27.880989189Z", - "DeletedAt": null, - "smart_id": 6, - "attribute_id": "write.errors_corrected_by_rereads_rewrites", - "name": "Write Errors Corrected by ReReads/ReWrites", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 206, - "CreatedAt": "2020-09-08T21:39:26.580579-07:00", - "UpdatedAt": "2020-09-08T21:39:26.580579-07:00", - "DeletedAt": null, - "smart_id": 48, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 180, - "CreatedAt": "2020-09-07T15:47:21.349306435Z", - "UpdatedAt": "2020-09-07T15:47:21.349306435Z", - "DeletedAt": null, - "smart_id": 42, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 154, - "CreatedAt": "2020-09-07T15:38:56.643981692Z", - "UpdatedAt": "2020-09-07T15:38:56.643981692Z", - "DeletedAt": null, - "smart_id": 36, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 128, - "CreatedAt": "2020-09-07T15:26:07.518286712Z", - "UpdatedAt": "2020-09-07T15:26:07.518286712Z", - "DeletedAt": null, - "smart_id": 30, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 102, - "CreatedAt": "2020-09-07T15:19:17.479270845Z", - "UpdatedAt": "2020-09-07T15:19:17.479270845Z", - "DeletedAt": null, - "smart_id": 24, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 76, - "CreatedAt": "2020-09-07T15:10:40.258142985Z", - "UpdatedAt": "2020-09-07T15:10:40.258142985Z", - "DeletedAt": null, - "smart_id": 18, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 50, - "CreatedAt": "2020-09-06T23:14:39.859534584Z", - "UpdatedAt": "2020-09-06T23:14:39.859534584Z", - "DeletedAt": null, - "smart_id": 12, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 24, - "CreatedAt": "2020-08-28T07:55:27.881076285Z", - "UpdatedAt": "2020-08-28T07:55:27.881076285Z", - "DeletedAt": null, - "smart_id": 6, - "attribute_id": "write.total_errors_corrected", - "name": "Write Total Errors Corrected", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 207, - "CreatedAt": "2020-09-08T21:39:26.580636-07:00", - "UpdatedAt": "2020-09-08T21:39:26.580636-07:00", - "DeletedAt": null, - "smart_id": 48, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": -1, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 181, - "CreatedAt": "2020-09-07T15:47:21.349410535Z", - "UpdatedAt": "2020-09-07T15:47:21.349410535Z", - "DeletedAt": null, - "smart_id": 42, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 155, - "CreatedAt": "2020-09-07T15:38:56.644047493Z", - "UpdatedAt": "2020-09-07T15:38:56.644047493Z", - "DeletedAt": null, - "smart_id": 36, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 129, - "CreatedAt": "2020-09-07T15:26:07.518360714Z", - "UpdatedAt": "2020-09-07T15:26:07.518360714Z", - "DeletedAt": null, - "smart_id": 30, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 103, - "CreatedAt": "2020-09-07T15:19:17.479342345Z", - "UpdatedAt": "2020-09-07T15:19:17.479342345Z", - "DeletedAt": null, - "smart_id": 24, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 77, - "CreatedAt": "2020-09-07T15:10:40.258232186Z", - "UpdatedAt": "2020-09-07T15:10:40.258232186Z", - "DeletedAt": null, - "smart_id": 18, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 51, - "CreatedAt": "2020-09-06T23:14:39.859593786Z", - "UpdatedAt": "2020-09-06T23:14:39.859593786Z", - "DeletedAt": null, - "smart_id": 12, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 25, - "CreatedAt": "2020-08-28T07:55:27.881149036Z", - "UpdatedAt": "2020-08-28T07:55:27.881149036Z", - "DeletedAt": null, - "smart_id": 6, - "attribute_id": "write.correction_algorithm_invocations", - "name": "Write Correction Algorithm Invocations", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }] - }, { - "ID": 208, - "CreatedAt": "2020-09-08T21:39:26.5807-07:00", - "UpdatedAt": "2020-09-08T21:39:26.5807-07:00", - "DeletedAt": null, - "smart_id": 48, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0, - "status": "passed", - "history": [{ - "ID": 182, - "CreatedAt": "2020-09-07T15:47:21.350041836Z", - "UpdatedAt": "2020-09-07T15:47:21.350041836Z", - "DeletedAt": null, - "smart_id": 42, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 156, - "CreatedAt": "2020-09-07T15:38:56.644111093Z", - "UpdatedAt": "2020-09-07T15:38:56.644111093Z", - "DeletedAt": null, - "smart_id": 36, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 130, - "CreatedAt": "2020-09-07T15:26:07.518435116Z", - "UpdatedAt": "2020-09-07T15:26:07.518435116Z", - "DeletedAt": null, - "smart_id": 30, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 104, - "CreatedAt": "2020-09-07T15:19:17.479407945Z", - "UpdatedAt": "2020-09-07T15:19:17.479407945Z", - "DeletedAt": null, - "smart_id": 24, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 78, - "CreatedAt": "2020-09-07T15:10:40.258301886Z", - "UpdatedAt": "2020-09-07T15:10:40.258301886Z", - "DeletedAt": null, - "smart_id": 18, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 52, - "CreatedAt": "2020-09-06T23:14:39.859652488Z", - "UpdatedAt": "2020-09-06T23:14:39.859652488Z", - "DeletedAt": null, - "smart_id": 12, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", - "value": 0, - "thresh": 0, - "transformed_value": 0 - }, { - "ID": 26, - "CreatedAt": "2020-08-28T07:55:27.881226699Z", - "UpdatedAt": "2020-08-28T07:55:27.881226699Z", - "DeletedAt": null, - "smart_id": 6, - "attribute_id": "write.total_uncorrected_errors", - "name": "Write Total Uncorrected Errors", + "thresh": -1, + "transformed_value": 0, + "status": 0 + }, + "read_total_uncorrected_errors": { + "attribute_id": "read_total_uncorrected_errors", + "value": 0, + "thresh": 0, + "transformed_value": 0, + "status": 0 + }, + "scsi_grown_defect_list": { + "attribute_id": "scsi_grown_defect_list", "value": 0, "thresh": 0, - "transformed_value": 0 - }] - }] + "transformed_value": 0, + "status": 0 + }, + "write_correction_algorithm_invocations": { + "attribute_id": "write_correction_algorithm_invocations", + "value": 0, + "thresh": -1, + "transformed_value": 0, + "status": 0 + }, + "write_errors_corrected_by_eccdelayed": { + "attribute_id": "write_errors_corrected_by_eccdelayed", + "value": 0, + "thresh": -1, + "transformed_value": 0, + "status": 0 + }, + "write_errors_corrected_by_eccfast": { + "attribute_id": "write_errors_corrected_by_eccfast", + "value": 0, + "thresh": -1, + "transformed_value": 0, + "status": 0 + }, + "write_errors_corrected_by_rereads_rewrites": { + "attribute_id": "write_errors_corrected_by_rereads_rewrites", + "value": 0, + "thresh": 0, + "transformed_value": 0, + "status": 0 + }, + "write_total_errors_corrected": { + "attribute_id": "write_total_errors_corrected", + "value": 0, + "thresh": -1, + "transformed_value": 0, + "status": 0 + }, + "write_total_uncorrected_errors": { + "attribute_id": "write_total_uncorrected_errors", + "value": 0, + "thresh": 0, + "transformed_value": 0, + "status": 0 + } + }, + "Status": 0 }] - }, "metadata": { - "read.correction_algorithm_invocations": { + }, + "metadata": { + "read_correction_algorithm_invocations": { + "display_name": "Read Correction Algorithm Invocations", + "ideal": "", + "critical": false, + "description": "", + "display_type": "" + }, + "read_errors_corrected_by_eccdelayed": { + "display_name": "Read Errors Corrected by ECC Delayed", + "ideal": "", + "critical": false, + "description": "", + "display_type": "" + }, + "read_errors_corrected_by_eccfast": { + "display_name": "Read Errors Corrected by ECC Fast", + "ideal": "", + "critical": false, + "description": "", + "display_type": "" + }, + "read_errors_corrected_by_rereads_rewrites": { + "display_name": "Read Errors Corrected by ReReads/ReWrites", + "ideal": "low", + "critical": true, + "description": "", + "display_type": "" + }, + "read_total_errors_corrected": { + "display_name": "Read Total Errors Corrected", "ideal": "", "critical": false, "description": "", "display_type": "" }, - "read.errors_corrected_by_eccdelayed": {"ideal": "", "critical": false, "description": "", "display_type": ""}, - "read.errors_corrected_by_eccfast": {"ideal": "", "critical": false, "description": "", "display_type": ""}, - "read.errors_corrected_by_rereads_rewrites": { + "read_total_uncorrected_errors": { + "display_name": "Read Total Uncorrected Errors", "ideal": "low", "critical": true, "description": "", "display_type": "" }, - "read.total_errors_corrected": {"ideal": "", "critical": false, "description": "", "display_type": ""}, - "read.total_uncorrected_errors": {"ideal": "low", "critical": true, "description": "", "display_type": ""}, - "scsi_grown_defect_list": {"ideal": "low", "critical": true, "description": "", "display_type": ""}, - "write.correction_algorithm_invocations": { + "scsi_grown_defect_list": { + "display_name": "Grown Defect List", + "ideal": "low", + "critical": true, + "description": "", + "display_type": "" + }, + "write_correction_algorithm_invocations": { + "display_name": "Write Correction Algorithm Invocations", + "ideal": "", + "critical": false, + "description": "", + "display_type": "" + }, + "write_errors_corrected_by_eccdelayed": { + "display_name": "Write Errors Corrected by ECC Delayed", "ideal": "", "critical": false, "description": "", "display_type": "" }, - "write.errors_corrected_by_eccdelayed": {"ideal": "", "critical": false, "description": "", "display_type": ""}, - "write.errors_corrected_by_eccfast": {"ideal": "", "critical": false, "description": "", "display_type": ""}, - "write.errors_corrected_by_rereads_rewrites": { + "write_errors_corrected_by_eccfast": { + "display_name": "Write Errors Corrected by ECC Fast", + "ideal": "", + "critical": false, + "description": "", + "display_type": "" + }, + "write_errors_corrected_by_rereads_rewrites": { + "display_name": "Write Errors Corrected by ReReads/ReWrites", "ideal": "low", "critical": true, "description": "", "display_type": "" }, - "write.total_errors_corrected": {"ideal": "", "critical": false, "description": "", "display_type": ""}, - "write.total_uncorrected_errors": {"ideal": "low", "critical": true, "description": "", "display_type": ""} - }, "success": true + "write_total_errors_corrected": { + "display_name": "Write Total Errors Corrected", + "ideal": "", + "critical": false, + "description": "", + "display_type": "" + }, + "write_total_uncorrected_errors": { + "display_name": "Write Total Uncorrected Errors", + "ideal": "low", + "critical": true, + "description": "", + "display_type": "" + } + }, + "success": true } diff --git a/webapp/frontend/src/app/data/mock/device/details/sdf.ts b/webapp/frontend/src/app/data/mock/device/details/sdf.ts index c624dab..15949dd 100644 --- a/webapp/frontend/src/app/data/mock/device/details/sdf.ts +++ b/webapp/frontend/src/app/data/mock/device/details/sdf.ts @@ -1,1981 +1,29 @@ export const sdf = { "data": { "device": { - "CreatedAt": "2020-09-29T03:17:30.813487336Z", - "UpdatedAt": "2020-09-29T03:17:31.04293448Z", + "CreatedAt": "2021-06-24T21:17:31.305246-07:00", + "UpdatedAt": "2021-06-24T21:17:31.305246-07:00", "DeletedAt": null, - "wwn": "0x5000c500c0558f02", - "device_name": "sdc", - "manufacturer": "", - "model_name": "ST8000VN004-2M2101", - "interface_type": "", - "interface_speed": "6.0 Gb/s", - "serial_number": "WKD01Y5S", - "firmware": "SC60", - "rotational_speed": 7200, - "capacity": 8001563222016, - "form_factor": "3.5 inches", + "wwn": "0x50014ee20b2a72a9", + "device_name": "sdf", + "manufacturer": "ATA", + "model_name": "WDC_WD60EFRX-68MYMN1", + "interface_type": "SCSI", + "interface_speed": "", + "serial_number": "WD-WXL1HXXXXX", + "firmware": "", + "rotational_speed": 0, + "capacity": 6001175126016, + "form_factor": "", "smart_support": false, - "device_protocol": "ATA", - "device_type": "scsi", - "device_status": 2, - }, - "smart_results": [{ - "ID": 1, - "CreatedAt": "2020-09-29T03:17:31.063859162Z", - "UpdatedAt": "2020-09-29T03:17:31.063859162Z", - "DeletedAt": null, - "device_wwn": "0x5000c500c0558f02", - "date": "2020-09-29T03:17:30Z", - "smart_status": "passed", - "temp": 39, - "power_on_hours": 9499, - "power_cycle_count": 22, - "ata_attributes": [{ - "ID": 1, - "CreatedAt": "2020-09-29T03:17:31.064174997Z", - "UpdatedAt": "2020-09-29T03:17:31.064174997Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 79, - "worst": 64, - "thresh": 44, - "raw_value": 78022392, - "raw_string": "78022392", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 2, - "CreatedAt": "2020-09-29T03:17:31.064379412Z", - "UpdatedAt": "2020-09-29T03:17:31.064379412Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 95, - "worst": 86, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "warn", - "status_reason": "Observed Failure Rate for Attribute is greater than 10%", - "failure_rate": 0.11452195377351217 - }, { - "ID": 3, - "CreatedAt": "2020-09-29T03:17:31.064506775Z", - "UpdatedAt": "2020-09-29T03:17:31.064506775Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 20, - "raw_value": 220, - "raw_string": "220", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 4, - "CreatedAt": "2020-09-29T03:17:31.064621265Z", - "UpdatedAt": "2020-09-29T03:17:31.064621265Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 10, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.025169175350572493 - }, { - "ID": 5, - "CreatedAt": "2020-09-29T03:17:31.064742769Z", - "UpdatedAt": "2020-09-29T03:17:31.064742769Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 86, - "worst": 60, - "thresh": 45, - "raw_value": 4679507461, - "raw_string": "4679507461", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.08725919610118257 - }, { - "ID": 6, - "CreatedAt": "2020-09-29T03:17:31.064850152Z", - "UpdatedAt": "2020-09-29T03:17:31.064850152Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 90, - "worst": 90, - "thresh": 0, - "raw_value": 9499, - "raw_string": "9499", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 7, - "CreatedAt": "2020-09-29T03:17:31.064970318Z", - "UpdatedAt": "2020-09-29T03:17:31.064970318Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 97, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.05459827163896099 - }, { - "ID": 8, - "CreatedAt": "2020-09-29T03:17:31.065072898Z", - "UpdatedAt": "2020-09-29T03:17:31.065072898Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 20, - "raw_value": 22, - "raw_string": "22", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.038210930067894826 - }, { - "ID": 9, - "CreatedAt": "2020-09-29T03:17:31.065366547Z", - "UpdatedAt": "2020-09-29T03:17:31.065366547Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 18, - "name": "Unknown_Attribute", - "value": 100, - "worst": 100, - "thresh": 50, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 10, - "CreatedAt": "2020-09-29T03:17:31.065539403Z", - "UpdatedAt": "2020-09-29T03:17:31.065539403Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 187, - "name": "Reported Uncorrectable Errors", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.028130798308190524 - }, { - "ID": 11, - "CreatedAt": "2020-09-29T03:17:31.065665808Z", - "UpdatedAt": "2020-09-29T03:17:31.065665808Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 188, - "name": "Command Timeout", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.024893587674442153 - }, { - "ID": 12, - "CreatedAt": "2020-09-29T03:17:31.065780779Z", - "UpdatedAt": "2020-09-29T03:17:31.065780779Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 190, - "name": "Temperature Difference", - "value": 61, - "worst": 46, - "thresh": 40, - "raw_value": 740294695, - "raw_string": "39 (Min/Max 32/44)", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 13, - "CreatedAt": "2020-09-29T03:17:31.065931499Z", - "UpdatedAt": "2020-09-29T03:17:31.065931499Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 4, - "raw_string": "4", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.0738571777154862 - }, { - "ID": 14, - "CreatedAt": "2020-09-29T03:17:31.066043189Z", - "UpdatedAt": "2020-09-29T03:17:31.066043189Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1680, - "raw_string": "1680", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 15, - "CreatedAt": "2020-09-29T03:17:31.066162028Z", - "UpdatedAt": "2020-09-29T03:17:31.066162028Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 194, - "name": "Temperature", - "value": 39, - "worst": 54, - "thresh": 0, - "raw_value": 81604378663, - "raw_string": "39 (0 19 0 0 0)", - "when_failed": "", - "transformed_value": 39, - "status": "passed" - }, { - "ID": 16, - "CreatedAt": "2020-09-29T03:17:31.066270283Z", - "UpdatedAt": "2020-09-29T03:17:31.066270283Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 195, - "name": "Hardware ECC Recovered", - "value": 79, - "worst": 64, - "thresh": 0, - "raw_value": 78022392, - "raw_string": "78022392", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 17, - "CreatedAt": "2020-09-29T03:17:31.066381938Z", - "UpdatedAt": "2020-09-29T03:17:31.066381938Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 197, - "name": "Current Pending Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.025540791394761345 - }, { - "ID": 18, - "CreatedAt": "2020-09-29T03:17:31.066497143Z", - "UpdatedAt": "2020-09-29T03:17:31.066497143Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.028675322159886437 - }, { - "ID": 19, - "CreatedAt": "2020-09-29T03:17:31.066632808Z", - "UpdatedAt": "2020-09-29T03:17:31.066632808Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", - "value": 200, - "worst": 200, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 20, - "CreatedAt": "2020-09-29T03:17:31.066757646Z", - "UpdatedAt": "2020-09-29T03:17:31.066757646Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 240, - "name": "Head Flying Hours", - "value": 100, - "worst": 253, - "thresh": 0, - "raw_value": 21887153349770, - "raw_string": "9354 (19 232 0)", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 21, - "CreatedAt": "2020-09-29T03:17:31.06687199Z", - "UpdatedAt": "2020-09-29T03:17:31.06687199Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 241, - "name": "Total LBAs Written", - "value": 100, - "worst": 253, - "thresh": 0, - "raw_value": 78115437520, - "raw_string": "78115437520", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 22, - "CreatedAt": "2020-09-29T03:17:31.066984948Z", - "UpdatedAt": "2020-09-29T03:17:31.066984948Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 242, - "name": "Total LBAs Read", - "value": 100, - "worst": 253, - "thresh": 0, - "raw_value": 226428055205, - "raw_string": "226428055205", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }], - "nvme_attributes": [], - "scsi_attributes": [] - }, { - "ID": 1, - "CreatedAt": "2020-09-29T03:17:31.063859162Z", - "UpdatedAt": "2020-09-29T03:17:31.063859162Z", - "DeletedAt": null, - "device_wwn": "0x5000c500c0558f02", - "date": "2020-09-29T03:17:30Z", - "smart_status": "passed", - "temp": 39, - "power_on_hours": 9499, - "power_cycle_count": 22, - "ata_attributes": [{ - "ID": 1, - "CreatedAt": "2020-09-29T03:17:31.064174997Z", - "UpdatedAt": "2020-09-29T03:17:31.064174997Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 1, - "name": "Read Error Rate", - "value": 79, - "worst": 64, - "thresh": 44, - "raw_value": 78022392, - "raw_string": "78022392", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 2, - "CreatedAt": "2020-09-29T03:17:31.064379412Z", - "UpdatedAt": "2020-09-29T03:17:31.064379412Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 3, - "name": "Spin-Up Time", - "value": 95, - "worst": 86, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "warn", - "status_reason": "Observed Failure Rate for Attribute is greater than 10%", - "failure_rate": 0.11452195377351217 - }, { - "ID": 3, - "CreatedAt": "2020-09-29T03:17:31.064506775Z", - "UpdatedAt": "2020-09-29T03:17:31.064506775Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 4, - "name": "Start/Stop Count", - "value": 100, - "worst": 100, - "thresh": 20, - "raw_value": 220, - "raw_string": "220", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 4, - "CreatedAt": "2020-09-29T03:17:31.064621265Z", - "UpdatedAt": "2020-09-29T03:17:31.064621265Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 5, - "name": "Reallocated Sectors Count", - "value": 100, - "worst": 100, - "thresh": 10, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.025169175350572493 - }, { - "ID": 5, - "CreatedAt": "2020-09-29T03:17:31.064742769Z", - "UpdatedAt": "2020-09-29T03:17:31.064742769Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 7, - "name": "Seek Error Rate", - "value": 86, - "worst": 60, - "thresh": 45, - "raw_value": 4679507461, - "raw_string": "4679507461", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.08725919610118257 - }, { - "ID": 6, - "CreatedAt": "2020-09-29T03:17:31.064850152Z", - "UpdatedAt": "2020-09-29T03:17:31.064850152Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 9, - "name": "Power-On Hours", - "value": 90, - "worst": 90, - "thresh": 0, - "raw_value": 9499, - "raw_string": "9499", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 7, - "CreatedAt": "2020-09-29T03:17:31.064970318Z", - "UpdatedAt": "2020-09-29T03:17:31.064970318Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 10, - "name": "Spin Retry Count", - "value": 100, - "worst": 100, - "thresh": 97, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.05459827163896099 - }, { - "ID": 8, - "CreatedAt": "2020-09-29T03:17:31.065072898Z", - "UpdatedAt": "2020-09-29T03:17:31.065072898Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 12, - "name": "Power Cycle Count", - "value": 100, - "worst": 100, - "thresh": 20, - "raw_value": 22, - "raw_string": "22", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.038210930067894826 - }, { - "ID": 9, - "CreatedAt": "2020-09-29T03:17:31.065366547Z", - "UpdatedAt": "2020-09-29T03:17:31.065366547Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 18, - "name": "Unknown_Attribute", - "value": 100, - "worst": 100, - "thresh": 50, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 10, - "CreatedAt": "2020-09-29T03:17:31.065539403Z", - "UpdatedAt": "2020-09-29T03:17:31.065539403Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 187, - "name": "Reported Uncorrectable Errors", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.028130798308190524 - }, { - "ID": 11, - "CreatedAt": "2020-09-29T03:17:31.065665808Z", - "UpdatedAt": "2020-09-29T03:17:31.065665808Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 188, - "name": "Command Timeout", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.024893587674442153 - }, { - "ID": 12, - "CreatedAt": "2020-09-29T03:17:31.065780779Z", - "UpdatedAt": "2020-09-29T03:17:31.065780779Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 190, - "name": "Temperature Difference", - "value": 61, - "worst": 46, - "thresh": 40, - "raw_value": 740294695, - "raw_string": "39 (Min/Max 32/44)", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 13, - "CreatedAt": "2020-09-29T03:17:31.065931499Z", - "UpdatedAt": "2020-09-29T03:17:31.065931499Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 192, - "name": "Power-off Retract Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 4, - "raw_string": "4", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.0738571777154862 - }, { - "ID": 14, - "CreatedAt": "2020-09-29T03:17:31.066043189Z", - "UpdatedAt": "2020-09-29T03:17:31.066043189Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 193, - "name": "Load Cycle Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 1680, - "raw_string": "1680", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 15, - "CreatedAt": "2020-09-29T03:17:31.066162028Z", - "UpdatedAt": "2020-09-29T03:17:31.066162028Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 194, - "name": "Temperature", - "value": 39, - "worst": 54, - "thresh": 0, - "raw_value": 81604378663, - "raw_string": "39 (0 19 0 0 0)", - "when_failed": "", - "transformed_value": 39, - "status": "passed" - }, { - "ID": 16, - "CreatedAt": "2020-09-29T03:17:31.066270283Z", - "UpdatedAt": "2020-09-29T03:17:31.066270283Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 195, - "name": "Hardware ECC Recovered", - "value": 79, - "worst": 64, - "thresh": 0, - "raw_value": 78022392, - "raw_string": "78022392", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 17, - "CreatedAt": "2020-09-29T03:17:31.066381938Z", - "UpdatedAt": "2020-09-29T03:17:31.066381938Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 197, - "name": "Current Pending Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.025540791394761345 - }, { - "ID": 18, - "CreatedAt": "2020-09-29T03:17:31.066497143Z", - "UpdatedAt": "2020-09-29T03:17:31.066497143Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 198, - "name": "(Offline) Uncorrectable Sector Count", - "value": 100, - "worst": 100, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed", - "failure_rate": 0.028675322159886437 - }, { - "ID": 19, - "CreatedAt": "2020-09-29T03:17:31.066632808Z", - "UpdatedAt": "2020-09-29T03:17:31.066632808Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 199, - "name": "UltraDMA CRC Error Count", - "value": 200, - "worst": 200, - "thresh": 0, - "raw_value": 0, - "raw_string": "0", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 20, - "CreatedAt": "2020-09-29T03:17:31.066757646Z", - "UpdatedAt": "2020-09-29T03:17:31.066757646Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 240, - "name": "Head Flying Hours", - "value": 100, - "worst": 253, - "thresh": 0, - "raw_value": 21887153349770, - "raw_string": "9354 (19 232 0)", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 21, - "CreatedAt": "2020-09-29T03:17:31.06687199Z", - "UpdatedAt": "2020-09-29T03:17:31.06687199Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 241, - "name": "Total LBAs Written", - "value": 100, - "worst": 253, - "thresh": 0, - "raw_value": 78115437520, - "raw_string": "78115437520", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }, { - "ID": 22, - "CreatedAt": "2020-09-29T03:17:31.066984948Z", - "UpdatedAt": "2020-09-29T03:17:31.066984948Z", - "DeletedAt": null, - "smart_id": 1, - "attribute_id": 242, - "name": "Total LBAs Read", - "value": 100, - "worst": 253, - "thresh": 0, - "raw_value": 226428055205, - "raw_string": "226428055205", - "when_failed": "", - "transformed_value": 0, - "status": "passed" - }], - "nvme_attributes": [], - "scsi_attributes": [] - }] - }, "metadata": { - "1": { - "ideal": "low", - "critical": false, - "description": "(Vendor specific raw value.) Stores data related to the rate of hardware read errors that occurred when reading data from a disk surface. The raw value has different structure for different vendors and is often not meaningful as a decimal number.", - "observed_thresholds": [{ - "low": 80, - "high": 95, - "annual_failure_rate": 0.8879749768303985, - "error_interval": [0.682344353388663, 1.136105732920724] - }, { - "low": 95, - "high": 110, - "annual_failure_rate": 0.034155719633986996, - "error_interval": [0.030188482024981093, 0.038499386872354435] - }, { - "low": 110, - "high": 125, - "annual_failure_rate": 0.06390002135229157, - "error_interval": [0.05852004676110847, 0.06964160930553712] - }, {"low": 125, "high": 140, "annual_failure_rate": 0, "error_interval": [0, 0]}, { - "low": 140, - "high": 155, - "annual_failure_rate": 0, - "error_interval": [0, 0] - }, {"low": 155, "high": 170, "annual_failure_rate": 0, "error_interval": [0, 0]}, { - "low": 170, - "high": 185, - "annual_failure_rate": 0, - "error_interval": [0, 0] - }, { - "low": 185, - "high": 200, - "annual_failure_rate": 0.044823775021490854, - "error_interval": [0.032022762038723306, 0.06103725943096589] - }], - "display_type": "normalized" - }, - "10": { - "ideal": "low", - "critical": true, - "description": "Count of retry of spin start attempts. This attribute stores a total count of the spin start attempts to reach the fully operational speed (under the condition that the first attempt was unsuccessful). An increase of this attribute value is a sign of problems in the hard disk mechanical subsystem.", - "observed_thresholds": [{ - "low": 0, - "high": 0, - "annual_failure_rate": 0.05459827163896099, - "error_interval": [0.05113785787727033, 0.05823122757702782] - }, { - "low": 0, - "high": 80, - "annual_failure_rate": 0.5555555555555556, - "error_interval": [0.014065448880161053, 3.095357439410498] - }], - "display_type": "raw" - }, - "11": { - "ideal": "low", - "critical": false, - "description": "This attribute indicates the count that recalibration was requested (under the condition that the first attempt was unsuccessful). An increase of this attribute value is a sign of problems in the hard disk mechanical subsystem.", - "observed_thresholds": [{ - "low": 0, - "high": 0, - "annual_failure_rate": 0.04658866433672694, - "error_interval": [0.03357701137320878, 0.06297433993055492] - }, { - "low": 0, - "high": 80, - "annual_failure_rate": 0.5555555555555556, - "error_interval": [0.014065448880161053, 3.095357439410498] - }, {"low": 80, "high": 160, "annual_failure_rate": 0, "error_interval": [0, 0]}, { - "low": 160, - "high": 240, - "annual_failure_rate": 0, - "error_interval": [0, 0] - }, {"low": 240, "high": 320, "annual_failure_rate": 0, "error_interval": [0, 0]}, { - "low": 320, - "high": 400, - "annual_failure_rate": 0, - "error_interval": [0, 0] - }, {"low": 400, "high": 480, "annual_failure_rate": 0, "error_interval": [0, 0]}, { - "low": 480, - "high": 560, - "annual_failure_rate": 0, - "error_interval": [0, 0] - }], - "display_type": "raw" - }, - "12": { - "ideal": "low", - "critical": false, - "description": "This attribute indicates the count of full hard disk power on/off cycles.", - "observed_thresholds": [{ - "low": 0, - "high": 13, - "annual_failure_rate": 0.019835987118930823, - "error_interval": [0.016560870164523494, 0.023569242386797896] - }, { - "low": 13, - "high": 26, - "annual_failure_rate": 0.038210930067894826, - "error_interval": [0.03353859179329295, 0.0433520775718649] - }, { - "low": 26, - "high": 39, - "annual_failure_rate": 0.11053528307302571, - "error_interval": [0.09671061589521368, 0.1257816678419765] - }, { - "low": 39, - "high": 52, - "annual_failure_rate": 0.16831189443375036, - "error_interval": [0.1440976510675928, 0.19543066007594895] - }, { - "low": 52, - "high": 65, - "annual_failure_rate": 0.20630344262550107, - "error_interval": [0.1693965932069108, 0.2488633537247856] - }, { - "low": 65, - "high": 78, - "annual_failure_rate": 0.1030972634140512, - "error_interval": [0.06734655535304743, 0.15106137807407605] - }, { - "low": 78, - "high": 91, - "annual_failure_rate": 0.12354840389522469, - "error_interval": [0.06578432170016109, 0.21127153335749593] - }], - "display_type": "raw" - }, - "13": { - "ideal": "low", - "critical": false, - "description": "Uncorrected read errors reported to the operating system.", - "display_type": "normalized" - }, - "170": {"ideal": "", "critical": false, "description": "See attribute E8.", "display_type": "normalized"}, - "171": { - "ideal": "", - "critical": false, - "description": "(Kingston) The total number of flash program operation failures since the drive was deployed.[33] Identical to attribute 181.", - "display_type": "normalized" - }, - "172": { - "ideal": "", - "critical": false, - "description": "(Kingston) Counts the number of flash erase failures. This attribute returns the total number of Flash erase operation failures since the drive was deployed. This attribute is identical to attribute 182.", - "display_type": "normalized" - }, - "173": { - "ideal": "", - "critical": false, - "description": "Counts the maximum worst erase count on any block.", - "display_type": "normalized" - }, - "174": { - "ideal": "", - "critical": false, - "description": "Also known as Power-off Retract Count per conventional HDD terminology. Raw value reports the number of unclean shutdowns, cumulative over the life of an SSD, where an unclean shutdown is the removal of power without STANDBY IMMEDIATE as the last command (regardless of PLI activity using capacitor power). Normalized value is always 100.", - "display_type": "" - }, - "175": { - "ideal": "", - "critical": false, - "description": "Last test result as microseconds to discharge cap, saturated at its maximum value. Also logs minutes since last test and lifetime number of tests. Raw value contains the following data: Bytes 0-1: Last test result as microseconds to discharge cap, saturates at max value. Test result expected in range 25 \\u003c= result \\u003c= 5000000, lower indicates specific error code. Bytes 2-3: Minutes since last test, saturates at max value.Bytes 4-5: Lifetime number of tests, not incremented on power cycle, saturates at max value. Normalized value is set to one on test failure or 11 if the capacitor has been tested in an excessive temperature condition, otherwise 100.", - "display_type": "normalized" - }, - "176": { - "ideal": "", - "critical": false, - "description": "S.M.A.R.T. parameter indicates a number of flash erase command failures.", - "display_type": "normalized" - }, - "177": { - "ideal": "", - "critical": false, - "description": "Delta between most-worn and least-worn Flash blocks. It describes how good/bad the wearleveling of the SSD works on a more technical way. ", - "display_type": "normalized" - }, - "179": { - "ideal": "", - "critical": false, - "description": "Pre-Fail attribute used at least in Samsung devices.", - "display_type": "normalized" - }, - "180": { - "ideal": "", - "critical": false, - "description": "Pre-Fail attribute used at least in HP devices. ", - "display_type": "normalized" - }, - "181": { - "ideal": "", - "critical": false, - "description": "Total number of Flash program operation failures since the drive was deployed.", - "display_type": "normalized" - }, - "182": { - "ideal": "", - "critical": false, - "description": "Pre-Fail Attribute used at least in Samsung devices.", - "display_type": "normalized" - }, - "183": { - "ideal": "low", - "critical": false, - "description": "Western Digital, Samsung or Seagate attribute: Either the number of downshifts of link speed (e.g. from 6Gbit/s to 3Gbit/s) or the total number of data blocks with detected, uncorrectable errors encountered during normal operation. Although degradation of this parameter can be an indicator of drive aging and/or potential electromechanical problems, it does not directly indicate imminent drive failure.", - "observed_thresholds": [{ - "low": 0, - "high": 0, - "annual_failure_rate": 0.09084549203210031, - "error_interval": [0.08344373475686712, 0.09872777224842152] - }, { - "low": 1, - "high": 2, - "annual_failure_rate": 0.05756065656498585, - "error_interval": [0.04657000847949464, 0.07036491775108872] - }, { - "low": 2, - "high": 4, - "annual_failure_rate": 0.6193088626208925, - "error_interval": [0.41784508895529787, 0.8841019099092139] - }, { - "low": 4, - "high": 8, - "annual_failure_rate": 0.5533447034299792, - "error_interval": [0.31628430884775033, 0.8985971312402635] - }, { - "low": 8, - "high": 16, - "annual_failure_rate": 0.3882388694727245, - "error_interval": [0.21225380267814295, 0.6513988534774338] - }, { - "low": 16, - "high": 35, - "annual_failure_rate": 0.37116708385481856, - "error_interval": [0.19763084005134446, 0.6347070173754686] - }, { - "low": 35, - "high": 70, - "annual_failure_rate": 0.2561146752205292, - "error_interval": [0.10297138269895259, 0.5276941165819332] - }, { - "low": 70, - "high": 130, - "annual_failure_rate": 0.40299684542586756, - "error_interval": [0.16202563309223209, 0.8303275247667772] - }, {"low": 130, "high": 260, "annual_failure_rate": 0, "error_interval": [0, 0]}], - "display_type": "raw" - }, - "184": { - "ideal": "low", - "critical": true, - "description": "This attribute is a part of Hewlett-Packards SMART IV technology, as well as part of other vendors IO Error Detection and Correction schemas, and it contains a count of parity errors which occur in the data path to the media via the drives cache RAM", - "observed_thresholds": [{ - "low": 93, - "high": 94, - "annual_failure_rate": 1.631212012870933, - "error_interval": [1.055634407303844, 2.407990716767714] - }, {"low": 94, "high": 95, "annual_failure_rate": 0, "error_interval": [0, 0]}, { - "low": 95, - "high": 96, - "annual_failure_rate": 0, - "error_interval": [0, 0] - }, {"low": 96, "high": 97, "annual_failure_rate": 0, "error_interval": [0, 0]}, { - "low": 97, - "high": 97, - "annual_failure_rate": 0, - "error_interval": [0, 0] - }, { - "low": 97, - "high": 98, - "annual_failure_rate": 1.8069306930693072, - "error_interval": [0.04574752432804858, 10.067573453924245] - }, { - "low": 98, - "high": 99, - "annual_failure_rate": 0.8371559633027523, - "error_interval": [0.10138347095016888, 3.0240951820174824] - }, { - "low": 99, - "high": 100, - "annual_failure_rate": 0.09334816849865138, - "error_interval": [0.08689499010435861, 0.10015372448181788] - }], - "display_type": "normalized" - }, - "185": { - "ideal": "", - "critical": false, - "description": "Western Digital attribute.", - "display_type": "normalized" - }, - "186": { - "ideal": "", - "critical": false, - "description": "Western Digital attribute.", - "display_type": "normalized" - }, - "187": { - "ideal": "low", - "critical": true, - "description": "The count of errors that could not be recovered using hardware ECC (see attribute 195).", - "observed_thresholds": [{ - "low": 0, - "high": 0, - "annual_failure_rate": 0.028130798308190524, - "error_interval": [0.024487830609364304, 0.032162944988161336] - }, { - "low": 1, - "high": 1, - "annual_failure_rate": 0.33877621175661743, - "error_interval": [0.22325565823630591, 0.4929016016666955] - }, { - "low": 1, - "high": 3, - "annual_failure_rate": 0.24064820598237213, - "error_interval": [0.14488594021076606, 0.3758019832614595] - }, { - "low": 3, - "high": 6, - "annual_failure_rate": 0.5014425058387142, - "error_interval": [0.3062941096766342, 0.7744372808405151] - }, { - "low": 6, - "high": 11, - "annual_failure_rate": 0.38007108544136836, - "error_interval": [0.2989500188963677, 0.4764223967570595] - }, { - "low": 11, - "high": 20, - "annual_failure_rate": 0.5346094598348444, - "error_interval": [0.40595137663302483, 0.6911066985735377] - }, { - "low": 20, - "high": 35, - "annual_failure_rate": 0.8428063943161636, - "error_interval": [0.6504601819243522, 1.0742259350903411] - }, { - "low": 35, - "high": 65, - "annual_failure_rate": 1.4429071005017484, - "error_interval": [1.1405581860945952, 1.8008133631629157] - }, { - "low": 65, - "high": 120, - "annual_failure_rate": 1.6190935390549661, - "error_interval": [1.0263664163011208, 2.4294352761068576] - }], - "display_type": "raw" - }, - "188": { - "ideal": "low", - "critical": true, - "description": "The count of aborted operations due to HDD timeout. Normally this attribute value should be equal to zero.", - "observed_thresholds": [{ - "low": 0, - "high": 0, - "annual_failure_rate": 0.024893587674442153, - "error_interval": [0.020857343769186413, 0.0294830350167543] - }, { - "low": 0, - "high": 13, - "annual_failure_rate": 0.10044174089362015, - "error_interval": [0.0812633664077498, 0.1227848196758574] - }, { - "low": 13, - "high": 26, - "annual_failure_rate": 0.334030592234279, - "error_interval": [0.2523231196342665, 0.4337665082489293] - }, { - "low": 26, - "high": 39, - "annual_failure_rate": 0.36724705400842445, - "error_interval": [0.30398009356575617, 0.4397986538328568] - }, { - "low": 39, - "high": 52, - "annual_failure_rate": 0.29848155926978354, - "error_interval": [0.2509254838615984, 0.35242890006477073] - }, { - "low": 52, - "high": 65, - "annual_failure_rate": 0.2203079701535098, - "error_interval": [0.18366082845676174, 0.26212468677179274] - }, { - "low": 65, - "high": 78, - "annual_failure_rate": 0.3018169948863018, - "error_interval": [0.23779746376787655, 0.37776897542831006] - }, { - "low": 78, - "high": 91, - "annual_failure_rate": 0.32854928239235887, - "error_interval": [0.2301118782147336, 0.4548506948185028] - }, { - "low": 91, - "high": 104, - "annual_failure_rate": 0.28488916640649387, - "error_interval": [0.1366154288236293, 0.5239213202729072] - }], - "display_type": "raw" - }, - "189": { - "ideal": "low", - "critical": false, - "description": "HDD manufacturers implement a flying height sensor that attempts to provide additional protections for write operations by detecting when a recording head is flying outside its normal operating range. If an unsafe fly height condition is encountered, the write process is stopped, and the information is rewritten or reallocated to a safe region of the hard drive. This attribute indicates the count of these errors detected over the lifetime of the drive.", - "observed_thresholds": [{ - "low": 0, - "high": 0, - "annual_failure_rate": 0.09070551401946862, - "error_interval": [0.08018892683853401, 0.10221801211956287] - }, { - "low": 1, - "high": 2, - "annual_failure_rate": 0.0844336097370013, - "error_interval": [0.07299813695315267, 0.09715235540340669] - }, { - "low": 2, - "high": 5, - "annual_failure_rate": 0.07943219628781906, - "error_interval": [0.06552176680630226, 0.09542233189887633] - }, { - "low": 5, - "high": 13, - "annual_failure_rate": 0.09208847603893404, - "error_interval": [0.07385765060838133, 0.11345557807163456] - }, { - "low": 13, - "high": 30, - "annual_failure_rate": 0.18161161650924224, - "error_interval": [0.13858879602902988, 0.23377015012749933] - }, { - "low": 30, - "high": 70, - "annual_failure_rate": 0.2678117886102384, - "error_interval": [0.19044036194841887, 0.36610753129699186] - }, { - "low": 70, - "high": 150, - "annual_failure_rate": 0.26126480798826107, - "error_interval": [0.15958733218826962, 0.4035023060905559] - }, { - "low": 150, - "high": 350, - "annual_failure_rate": 0.11337164155924832, - "error_interval": [0.030889956621649995, 0.2902764300762812] - }], - "display_type": "raw" - }, - "190": { - "ideal": "", - "critical": false, - "description": "Value is equal to (100-temp. °C), allowing manufacturer to set a minimum threshold which corresponds to a maximum temperature. This also follows the convention of 100 being a best-case value and lower values being undesirable. However, some older drives may instead report raw Temperature (identical to 0xC2) or Temperature minus 50 here.", - "display_type": "normalized" - }, - "191": { - "ideal": "low", - "critical": false, - "description": "The count of errors resulting from externally induced shock and vibration. ", - "display_type": "normalized" - }, - "192": { - "ideal": "low", - "critical": false, - "description": "Number of power-off or emergency retract cycles.", - "observed_thresholds": [{ - "low": 1, - "high": 2, - "annual_failure_rate": 0.02861098445412803, - "error_interval": [0.022345416230915037, 0.036088863823297186] - }, { - "low": 2, - "high": 6, - "annual_failure_rate": 0.0738571777154862, - "error_interval": [0.06406927746420421, 0.0847175264009771] - }, { - "low": 6, - "high": 16, - "annual_failure_rate": 0.11970378206823593, - "error_interval": [0.10830059875098269, 0.13198105985656441] - }, { - "low": 16, - "high": 40, - "annual_failure_rate": 0.027266868552620425, - "error_interval": [0.021131448605713823, 0.03462795920968522] - }, { - "low": 40, - "high": 100, - "annual_failure_rate": 0.011741682974559688, - "error_interval": [0.00430899071133239, 0.025556700631152028] - }, { - "low": 100, - "high": 250, - "annual_failure_rate": 0.012659940134091309, - "error_interval": [0.00607093338127348, 0.023282080653656938] - }, { - "low": 250, - "high": 650, - "annual_failure_rate": 0.01634692899031039, - "error_interval": [0.009522688540043157, 0.026173016865409605] - }, { - "low": 650, - "high": 1600, - "annual_failure_rate": 0.005190074354440066, - "error_interval": [0.0025908664180103293, 0.009286476666453648] - }], - "display_type": "raw" - }, - "193": { - "ideal": "low", - "critical": false, - "description": "Count of load/unload cycles into head landing zone position.[45] Some drives use 225 (0xE1) for Load Cycle Count instead.", - "display_type": "normalized" - }, - "194": { - "ideal": "low", - "critical": false, - "description": "Indicates the device temperature, if the appropriate sensor is fitted. Lowest byte of the raw value contains the exact temperature value (Celsius degrees).", - "transform_value_unit": "°C", - "display_type": "transformed" - }, - "195": { - "ideal": "", - "critical": false, - "description": "(Vendor-specific raw value.) The raw value has different structure for different vendors and is often not meaningful as a decimal number.", - "observed_thresholds": [{ - "low": 12, - "high": 24, - "annual_failure_rate": 0.31472916829975706, - "error_interval": [0.15711166685282174, 0.5631374192486645] - }, { - "low": 24, - "high": 36, - "annual_failure_rate": 0.15250310197260136, - "error_interval": [0.10497611828070175, 0.21417105521823687] - }, { - "low": 36, - "high": 48, - "annual_failure_rate": 0.2193119102723874, - "error_interval": [0.16475385681835103, 0.28615447006525274] - }, { - "low": 48, - "high": 60, - "annual_failure_rate": 0.05672658497265746, - "error_interval": [0.043182904776447234, 0.07317316161437043] - }, {"low": 60, "high": 72, "annual_failure_rate": 0, "error_interval": [0, 0]}, { - "low": 72, - "high": 84, - "annual_failure_rate": 0, - "error_interval": [0, 0] - }, {"low": 84, "high": 96, "annual_failure_rate": 0, "error_interval": [0, 0]}, { - "low": 96, - "high": 108, - "annual_failure_rate": 0.04074570216566197, - "error_interval": [0.001031591863615295, 0.22702052218047528] - }], - "display_type": "normalized" - }, - "196": { - "ideal": "low", - "critical": true, - "description": "Count of remap operations. The raw value of this attribute shows the total count of attempts to transfer data from reallocated sectors to a spare area. Both successful and unsuccessful attempts are counted.", - "observed_thresholds": [{ - "low": 0, - "high": 0, - "annual_failure_rate": 0.007389855800729792, - "error_interval": [0.005652654139732716, 0.009492578928212054] - }, { - "low": 1, - "high": 1, - "annual_failure_rate": 0.026558331312151347, - "error_interval": [0.005476966404484466, 0.07761471429677293] - }, { - "low": 1, - "high": 2, - "annual_failure_rate": 0.02471894893674658, - "error_interval": [0.0006258296027540169, 0.13772516847438018] - }, { - "low": 2, - "high": 4, - "annual_failure_rate": 0.03200912040691046, - "error_interval": [0.0008104007642081744, 0.17834340416493005] - }, { - "low": 4, - "high": 7, - "annual_failure_rate": 0.043078012510326925, - "error_interval": [0.001090640849081295, 0.24001532369794615] - }, { - "low": 7, - "high": 11, - "annual_failure_rate": 0.033843300880853036, - "error_interval": [0.0008568381932559863, 0.18856280368036135] - }, { - "low": 11, - "high": 17, - "annual_failure_rate": 0.16979376647542252, - "error_interval": [0.035015556653263225, 0.49620943874336304] - }, { - "low": 17, - "high": 27, - "annual_failure_rate": 0.059042381106438044, - "error_interval": [0.0014948236677880642, 0.32896309247698113] - }, { - "low": 27, - "high": 45, - "annual_failure_rate": 0.24701105346266636, - "error_interval": [0.050939617608142244, 0.721871118983972] - }], - "display_type": "raw" - }, - "197": { - "ideal": "low", - "critical": true, - "description": "Count of unstable sectors (waiting to be remapped, because of unrecoverable read errors). If an unstable sector is subsequently read successfully, the sector is remapped and this value is decreased. Read errors on a sector will not remap the sector immediately (since the correct value cannot be read and so the value to remap is not known, and also it might become readable later); instead, the drive firmware remembers that the sector needs to be remapped, and will remap it the next time its written.", - "observed_thresholds": [{ - "low": 0, - "high": 0, - "annual_failure_rate": 0.025540791394761345, - "error_interval": [0.023161777231213983, 0.02809784482748174] - }, { - "low": 1, - "high": 2, - "annual_failure_rate": 0.34196613799103254, - "error_interval": [0.22723401523750225, 0.4942362818474496] - }, { - "low": 2, - "high": 6, - "annual_failure_rate": 0.6823772508117681, - "error_interval": [0.41083568090070416, 1.0656166047061635] - }, { - "low": 6, - "high": 16, - "annual_failure_rate": 0.6108100007493069, - "error_interval": [0.47336936083368364, 0.7757071095273286] - }, { - "low": 16, - "high": 40, - "annual_failure_rate": 0.9564879341127684, - "error_interval": [0.7701044196378299, 1.174355230793638] - }, { - "low": 40, - "high": 100, - "annual_failure_rate": 1.6519989942167461, - "error_interval": [1.328402276482456, 2.0305872327541317] - }, { - "low": 100, - "high": 250, - "annual_failure_rate": 2.5137741046831956, - "error_interval": [1.9772427971560862, 3.1510376077891613] - }, { - "low": 250, - "high": 650, - "annual_failure_rate": 3.3203378817413904, - "error_interval": [2.5883662702274406, 4.195047163573006] - }, { - "low": 650, - "high": 1600, - "annual_failure_rate": 3.133047210300429, - "error_interval": [1.1497731080460096, 6.819324775707182] - }], - "display_type": "raw" - }, - "198": { - "ideal": "low", - "critical": true, - "description": "The total count of uncorrectable errors when reading/writing a sector. A rise in the value of this attribute indicates defects of the disk surface and/or problems in the mechanical subsystem.", - "observed_thresholds": [{ - "low": 0, - "high": 0, - "annual_failure_rate": 0.028675322159886437, - "error_interval": [0.026159385510707116, 0.03136793218577656] - }, { - "low": 0, - "high": 2, - "annual_failure_rate": 0.8135764944275583, - "error_interval": [0.40613445471964466, 1.4557130815309443] - }, { - "low": 2, - "high": 4, - "annual_failure_rate": 1.1173469387755102, - "error_interval": [0.5773494680315332, 1.9517802404552516] - }, { - "low": 4, - "high": 6, - "annual_failure_rate": 1.3558692421991083, - "error_interval": [0.4402470522980859, 3.1641465148237544] - }, { - "low": 6, - "high": 8, - "annual_failure_rate": 0.7324414715719062, - "error_interval": [0.15104704003805655, 2.140504796291604] - }, { - "low": 8, - "high": 10, - "annual_failure_rate": 0.5777213677766163, - "error_interval": [0.43275294849366835, 0.7556737733062419] - }, { - "low": 10, - "high": 12, - "annual_failure_rate": 1.7464114832535886, - "error_interval": [0.47583835092536914, 4.471507017371231] - }, { - "low": 12, - "high": 14, - "annual_failure_rate": 2.6449275362318843, - "error_interval": [0.3203129951758959, 9.554387676519005] - }, { - "low": 14, - "high": 16, - "annual_failure_rate": 0.796943231441048, - "error_interval": [0.5519063550198366, 1.113648286331181] - }], - "display_type": "raw" - }, - "199": { - "ideal": "low", - "critical": false, - "description": "The count of errors in data transfer via the interface cable as determined by ICRC (Interface Cyclic Redundancy Check).", - "observed_thresholds": [{ - "low": 0, - "high": 1, - "annual_failure_rate": 0.04068379316116366, - "error_interval": [0.037534031558106425, 0.04402730201866553] - }, { - "low": 1, - "high": 2, - "annual_failure_rate": 0.1513481259734218, - "error_interval": [0.12037165605991791, 0.18786293065527596] - }, { - "low": 2, - "high": 4, - "annual_failure_rate": 0.16849758722418978, - "error_interval": [0.12976367397863445, 0.2151676572000481] - }, { - "low": 4, - "high": 8, - "annual_failure_rate": 0.15385127340491614, - "error_interval": [0.10887431782430312, 0.21117289306426648] - }, { - "low": 8, - "high": 16, - "annual_failure_rate": 0.14882894050104387, - "error_interval": [0.09631424312463635, 0.2197008753522735] - }, { - "low": 16, - "high": 35, - "annual_failure_rate": 0.20878219917249793, - "error_interval": [0.14086447304552446, 0.29804957135975] - }, { - "low": 35, - "high": 70, - "annual_failure_rate": 0.13742940270409038, - "error_interval": [0.06860426267470295, 0.24589916335290812] - }, { - "low": 70, - "high": 130, - "annual_failure_rate": 0.22336578581363, - "error_interval": [0.11150339549604707, 0.39966309081252904] - }, { - "low": 130, - "high": 260, - "annual_failure_rate": 0.18277416124186283, - "error_interval": [0.07890890989692058, 0.3601379610272007] - }], - "display_type": "raw" - }, - "2": { - "ideal": "high", - "critical": false, - "description": "Overall (general) throughput performance of a hard disk drive. If the value of this attribute is decreasing there is a high probability that there is a problem with the disk.", - "display_type": "normalized" - }, - "200": { - "ideal": "low", - "critical": false, - "description": "The count of errors found when writing a sector. The higher the value, the worse the disks mechanical condition is.", - "display_type": "normalized" - }, - "201": { - "ideal": "low", - "critical": true, - "description": "Count indicates the number of uncorrectable software read errors.", - "display_type": "normalized" - }, - "202": { - "ideal": "low", - "critical": false, - "description": "Count of Data Address Mark errors (or vendor-specific).", - "display_type": "normalized" - }, - "203": { - "ideal": "low", - "critical": false, - "description": "The number of errors caused by incorrect checksum during the error correction.", - "display_type": "normalized" - }, - "204": { - "ideal": "low", - "critical": false, - "description": "Count of errors corrected by the internal error correction software.", - "display_type": "" - }, - "205": { - "ideal": "low", - "critical": false, - "description": "Count of errors due to high temperature.", - "display_type": "normalized" - }, - "206": { - "ideal": "", - "critical": false, - "description": "Height of heads above the disk surface. If too low, head crash is more likely; if too high, read/write errors are more likely.", - "display_type": "normalized" - }, - "207": { - "ideal": "low", - "critical": false, - "description": "Amount of surge current used to spin up the drive.", - "display_type": "normalized" - }, - "208": { - "ideal": "", - "critical": false, - "description": "Count of buzz routines needed to spin up the drive due to insufficient power.", - "display_type": "normalized" - }, - "209": { - "ideal": "", - "critical": false, - "description": "Drives seek performance during its internal tests.", - "display_type": "normalized" - }, - "210": { - "ideal": "", - "critical": false, - "description": "Found in Maxtor 6B200M0 200GB and Maxtor 2R015H1 15GB disks.", - "display_type": "normalized" - }, - "211": { - "ideal": "", - "critical": false, - "description": "A recording of a vibration encountered during write operations.", - "display_type": "normalized" - }, - "212": { - "ideal": "", - "critical": false, - "description": "A recording of shock encountered during write operations.", - "display_type": "normalized" - }, - "22": { - "ideal": "high", - "critical": false, - "description": "Specific to He8 drives from HGST. This value measures the helium inside of the drive specific to this manufacturer. It is a pre-fail attribute that trips once the drive detects that the internal environment is out of specification.", - "display_type": "normalized" - }, - "220": { - "ideal": "low", - "critical": false, - "description": "Distance the disk has shifted relative to the spindle (usually due to shock or temperature). Unit of measure is unknown.", - "display_type": "normalized" - }, - "221": { - "ideal": "low", - "critical": false, - "description": "The count of errors resulting from externally induced shock and vibration.", - "display_type": "normalized" - }, - "222": { - "ideal": "", - "critical": false, - "description": "Time spent operating under data load (movement of magnetic head armature).", - "display_type": "normalized" - }, - "223": { - "ideal": "", - "critical": false, - "description": "Count of times head changes position.", - "display_type": "normalized" - }, - "224": { - "ideal": "low", - "critical": false, - "description": "Resistance caused by friction in mechanical parts while operating.", - "display_type": "normalized" - }, - "225": { - "ideal": "low", - "critical": false, - "description": "Total count of load cycles Some drives use 193 (0xC1) for Load Cycle Count instead. See Description for 193 for significance of this number. ", - "display_type": "normalized" - }, - "226": { - "ideal": "", - "critical": false, - "description": "Total time of loading on the magnetic heads actuator (time not spent in parking area).", - "display_type": "normalized" - }, - "227": { - "ideal": "low", - "critical": false, - "description": "Count of attempts to compensate for platter speed variations.[66]", - "display_type": "" - }, - "228": { - "ideal": "low", - "critical": false, - "description": "The number of power-off cycles which are counted whenever there is a retract event and the heads are loaded off of the media such as when the machine is powered down, put to sleep, or is idle.", - "display_type": "" - }, - "230": { - "ideal": "", - "critical": false, - "description": "Amplitude of thrashing (repetitive head moving motions between operations).", - "display_type": "normalized" - }, - "231": { - "ideal": "", - "critical": false, - "description": "Indicates the approximate SSD life left, in terms of program/erase cycles or available reserved blocks. A normalized value of 100 represents a new drive, with a threshold value at 10 indicating a need for replacement. A value of 0 may mean that the drive is operating in read-only mode to allow data recovery.", - "display_type": "normalized" - }, - "232": { - "ideal": "", - "critical": false, - "description": "Number of physical erase cycles completed on the SSD as a percentage of the maximum physical erase cycles the drive is designed to endure.", - "display_type": "normalized" - }, - "233": { - "ideal": "", - "critical": false, - "description": "Intel SSDs report a normalized value from 100, a new drive, to a minimum of 1. It decreases while the NAND erase cycles increase from 0 to the maximum-rated cycles.", - "display_type": "normalized" - }, - "234": { - "ideal": "", - "critical": false, - "description": "Decoded as: byte 0-1-2 = average erase count (big endian) and byte 3-4-5 = max erase count (big endian).", - "display_type": "normalized" - }, - "235": { - "ideal": "", - "critical": false, - "description": "Decoded as: byte 0-1-2 = good block count (big endian) and byte 3-4 = system (free) block count.", - "display_type": "normalized" - }, - "240": { - "ideal": "", - "critical": false, - "description": "Time spent during the positioning of the drive heads.[15][71] Some Fujitsu drives report the count of link resets during a data transfer.", - "display_type": "normalized" - }, - "241": { - "ideal": "", - "critical": false, - "description": "Total count of LBAs written.", - "display_type": "normalized" - }, - "242": { - "ideal": "", - "critical": false, - "description": "Total count of LBAs read.Some S.M.A.R.T. utilities will report a negative number for the raw value since in reality it has 48 bits rather than 32.", - "display_type": "normalized" - }, - "243": { - "ideal": "", - "critical": false, - "description": "The upper 5 bytes of the 12-byte total number of LBAs written to the device. The lower 7 byte value is located at attribute 0xF1.", - "display_type": "normalized" - }, - "244": { - "ideal": "", - "critical": false, - "description": "The upper 5 bytes of the 12-byte total number of LBAs read from the device. The lower 7 byte value is located at attribute 0xF2.", - "display_type": "normalized" - }, - "249": { - "ideal": "", - "critical": false, - "description": "Total NAND Writes. Raw value reports the number of writes to NAND in 1 GB increments.", - "display_type": "normalized" - }, - "250": { - "ideal": "low", - "critical": false, - "description": "Count of errors while reading from a disk.", - "display_type": "normalized" - }, - "251": { - "ideal": "", - "critical": false, - "description": "The Minimum Spares Remaining attribute indicates the number of remaining spare blocks as a percentage of the total number of spare blocks available.", - "display_type": "normalized" - }, - "252": { - "ideal": "", - "critical": false, - "description": "The Newly Added Bad Flash Block attribute indicates the total number of bad flash blocks the drive detected since it was first initialized in manufacturing.", - "display_type": "normalized" - }, - "254": { - "ideal": "low", - "critical": false, - "description": "Count of Free Fall Events detected.", - "display_type": "normalized" - }, - "3": { - "ideal": "low", - "critical": false, - "description": "Average time of spindle spin up (from zero RPM to fully operational [milliseconds]).", - "observed_thresholds": [{ - "low": 78, - "high": 96, - "annual_failure_rate": 0.11452195377351217, - "error_interval": [0.10591837762295722, 0.12363823501915781] - }, { - "low": 96, - "high": 114, - "annual_failure_rate": 0.040274562840558074, - "error_interval": [0.03465055611002801, 0.046551312468303144] - }, { - "low": 114, - "high": 132, - "annual_failure_rate": 0.009100406705780476, - "error_interval": [0.006530608971356785, 0.012345729280075591] - }, { - "low": 132, - "high": 150, - "annual_failure_rate": 0.008561351734020232, - "error_interval": [0.004273795939256936, 0.015318623141355509] - }, { - "low": 150, - "high": 168, - "annual_failure_rate": 0.015780508262068848, - "error_interval": [0.005123888078524015, 0.03682644215646287] - }, { - "low": 168, - "high": 186, - "annual_failure_rate": 0.05262688124794024, - "error_interval": [0.0325768689524594, 0.08044577830285578] - }, { - "low": 186, - "high": 204, - "annual_failure_rate": 0.01957419424036038, - "error_interval": [0.0023705257325185624, 0.0707087198669825] - }, { - "low": 204, - "high": 222, - "annual_failure_rate": 0.026050959960031404, - "error_interval": [0.0006595532020744994, 0.1451466588889228] - }], - "display_type": "normalized" - }, - "4": { - "ideal": "", - "critical": false, - "description": "A tally of spindle start/stop cycles. The spindle turns on, and hence the count is increased, both when the hard disk is turned on after having before been turned entirely off (disconnected from power source) and when the hard disk returns from having previously been put to sleep mode.", - "observed_thresholds": [{ - "low": 0, - "high": 13, - "annual_failure_rate": 0.01989335424860646, - "error_interval": [0.016596548909440657, 0.023653263230617408] - }, { - "low": 13, - "high": 26, - "annual_failure_rate": 0.03776935438256488, - "error_interval": [0.03310396052098642, 0.04290806173460437] - }, { - "low": 26, - "high": 39, - "annual_failure_rate": 0.11022223828187004, - "error_interval": [0.09655110535164119, 0.12528657238811672] - }, { - "low": 39, - "high": 52, - "annual_failure_rate": 0.16289995457762474, - "error_interval": [0.13926541653588131, 0.18939614504497515] - }, { - "low": 52, - "high": 65, - "annual_failure_rate": 0.19358212432279714, - "error_interval": [0.15864522253849073, 0.23392418181765526] - }, { - "low": 65, - "high": 78, - "annual_failure_rate": 0.1157094940074447, - "error_interval": [0.07861898732346269, 0.16424039052527728] - }, { - "low": 78, - "high": 91, - "annual_failure_rate": 0.12262136155304391, - "error_interval": [0.0670382394080032, 0.20573780888032978] - }, {"low": 91, "high": 104, "annual_failure_rate": 0, "error_interval": [0, 0]}], - "display_type": "raw" - }, - "5": { - "ideal": "low", - "critical": true, - "description": "Count of reallocated sectors. The raw value represents a count of the bad sectors that have been found and remapped.Thus, the higher the attribute value, the more sectors the drive has had to reallocate. This value is primarily used as a metric of the life expectancy of the drive; a drive which has had any reallocations at all is significantly more likely to fail in the immediate months.", - "observed_thresholds": [{ - "low": 0, - "high": 0, - "annual_failure_rate": 0.025169175350572493, - "error_interval": [0.022768612038746357, 0.027753988579272894] - }, { - "low": 1, - "high": 4, - "annual_failure_rate": 0.027432608477803388, - "error_interval": [0.010067283827589948, 0.05970923963096652] - }, { - "low": 4, - "high": 16, - "annual_failure_rate": 0.07501976284584981, - "error_interval": [0.039944864177334186, 0.12828607921150972] - }, { - "low": 16, - "high": 70, - "annual_failure_rate": 0.23589260654405794, - "error_interval": [0.1643078435800227, 0.32806951196017664] - }, { - "low": 70, - "high": 260, - "annual_failure_rate": 0.36193219378600433, - "error_interval": [0.2608488901774093, 0.4892271827875412] - }, { - "low": 260, - "high": 1100, - "annual_failure_rate": 0.5676621428968173, - "error_interval": [0.4527895568499355, 0.702804359408436] - }, { - "low": 1100, - "high": 4500, - "annual_failure_rate": 1.5028253400346423, - "error_interval": [1.2681757596263297, 1.768305221795894] - }, { - "low": 4500, - "high": 17000, - "annual_failure_rate": 2.0659987547404763, - "error_interval": [1.6809790460512237, 2.512808045182302] - }, { - "low": 17000, - "high": 70000, - "annual_failure_rate": 1.7755385684503124, - "error_interval": [1.2796520259849835, 2.400012341226441] - }], - "display_type": "raw" - }, - "6": { - "ideal": "", - "critical": false, - "description": "Margin of a channel while reading data. The function of this attribute is not specified.", - "display_type": "normalized" - }, - "7": { - "ideal": "", - "critical": false, - "description": "(Vendor specific raw value.) Rate of seek errors of the magnetic heads. If there is a partial failure in the mechanical positioning system, then seek errors will arise. Such a failure may be due to numerous factors, such as damage to a servo, or thermal widening of the hard disk. The raw value has different structure for different vendors and is often not meaningful as a decimal number.", - "observed_thresholds": [{ - "low": 58, - "high": 76, - "annual_failure_rate": 0.2040131025936549, - "error_interval": [0.17032852883286412, 0.2424096283327138] - }, { - "low": 76, - "high": 94, - "annual_failure_rate": 0.08725919610118257, - "error_interval": [0.08077138510999876, 0.09412943212007528] - }, { - "low": 94, - "high": 112, - "annual_failure_rate": 0.01087335627722523, - "error_interval": [0.008732197944943352, 0.013380600544561905] - }, {"low": 112, "high": 130, "annual_failure_rate": 0, "error_interval": [0, 0]}, { - "low": 130, - "high": 148, - "annual_failure_rate": 0, - "error_interval": [0, 0] - }, {"low": 148, "high": 166, "annual_failure_rate": 0, "error_interval": [0, 0]}, { - "low": 166, - "high": 184, - "annual_failure_rate": 0, - "error_interval": [0, 0] - }, { - "low": 184, - "high": 202, - "annual_failure_rate": 0.05316285755900475, - "error_interval": [0.03370069132942804, 0.07977038905848267] - }], - "display_type": "normalized" - }, - "8": { - "ideal": "high", - "critical": false, - "description": "Average performance of seek operations of the magnetic heads. If this attribute is decreasing, it is a sign of problems in the mechanical subsystem.", - "display_type": "normalized" - }, - "9": { - "ideal": "", - "critical": false, - "description": "Count of hours in power-on state. The raw value of this attribute shows total count of hours (or minutes, or seconds, depending on manufacturer) in power-on state. By default, the total expected lifetime of a hard disk in perfect condition is defined as 5 years (running every day and night on all days). This is equal to 1825 days in 24/7 mode or 43800 hours. On some pre-2005 drives, this raw value may advance erratically and/or wrap around (reset to zero periodically).", - "display_type": "normalized" - } - }, "success": true + "device_protocol": "", + "device_type": "", + "label": "", + "host_id": "", + "device_status": 0 + }, + "smart_results": [] + }, + "metadata": null, + "success": true } diff --git a/webapp/frontend/src/app/modules/detail/detail.component.html b/webapp/frontend/src/app/modules/detail/detail.component.html index 7e9b15e..87597ca 100644 --- a/webapp/frontend/src/app/modules/detail/detail.component.html +++ b/webapp/frontend/src/app/modules/detail/detail.component.html @@ -139,15 +139,15 @@ - {{attribute.status}} + [ngClass]="{'bg-red': getAttributeStatusName(attribute.status) === 'failed', + 'bg-green': getAttributeStatusName(attribute.status) === 'passed', + 'bg-yellow': getAttributeStatusName(attribute.status) === 'warn'}"> + {{getAttributeStatusName(attribute.status)}} @@ -183,7 +183,7 @@ - {{attribute.name}} + {{getAttributeName(attribute)}} diff --git a/webapp/frontend/src/app/modules/detail/detail.component.ts b/webapp/frontend/src/app/modules/detail/detail.component.ts index df396b6..6f03bb5 100644 --- a/webapp/frontend/src/app/modules/detail/detail.component.ts +++ b/webapp/frontend/src/app/modules/detail/detail.component.ts @@ -107,6 +107,26 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { // ----------------------------------------------------------------------------------------------------- // @ Private methods // ----------------------------------------------------------------------------------------------------- + getAttributeStatusName(attribute_status){ + if(attribute_status == 0){ + return "passed" + } else if (attribute_status == 1){ + return "warn" + } else if (attribute_status == 2){ + return "failed" + } + return + } + + getAttributeName(attribute_data){ + let attribute_metadata = this.metadata[attribute_data.attribute_id] + if(!attribute_metadata){ + return 'Unknown Attribute Name' + } else { + return attribute_metadata.display_name + } + return + } getAttributeDescription(attribute_data){ let attribute_metadata = this.metadata[attribute_data.attribute_id] if(!attribute_metadata){ From 7b7b4fe4e3295ad1f7c1cf81156f643c2e1c7f63 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 24 Oct 2021 19:30:29 -0700 Subject: [PATCH 033/114] fixing test. --- webapp/backend/pkg/web/server_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webapp/backend/pkg/web/server_test.go b/webapp/backend/pkg/web/server_test.go index 01ec527..8f4a672 100644 --- a/webapp/backend/pkg/web/server_test.go +++ b/webapp/backend/pkg/web/server_test.go @@ -2,6 +2,7 @@ package web_test import ( "encoding/json" + "github.com/analogj/scrutiny/webapp/backend/pkg" mock_config "github.com/analogj/scrutiny/webapp/backend/pkg/config/mock" "github.com/analogj/scrutiny/webapp/backend/pkg/models" "github.com/analogj/scrutiny/webapp/backend/pkg/web" @@ -324,5 +325,5 @@ func TestGetDevicesSummaryRoute_Nvme(t *testing.T) { //assert require.Equal(t, "a4c8e8ed-11a0-4c97-9bba-306440f1b944", device.Data[0].WWN) - require.Equal(t, "passed", device.Data[0].SmartResults[0].SmartStatus) + require.Equal(t, pkg.DeviceStatusPassed, device.Data[0].DeviceStatus) } From c7603c8f62511327787976780d11b20f2aff560b Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 24 Oct 2021 22:05:28 -0700 Subject: [PATCH 034/114] karalabe/xgo-1.13.x is unmaintained, moving to techknowlogick/xgo:go-1.13.x --- .github/workflows/release.yaml | 2 +- docker/Dockerfile.xgo | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 1b830ea..cf26754 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -16,7 +16,7 @@ jobs: build: name: Build runs-on: ubuntu-latest - container: karalabe/xgo-1.13.x + container: techknowlogick/xgo:go-1.13.x env: PROJECT_PATH: /go/src/github.com/analogj/scrutiny CGO_ENABLED: 1 diff --git a/docker/Dockerfile.xgo b/docker/Dockerfile.xgo index 1bb32bd..1487949 100644 --- a/docker/Dockerfile.xgo +++ b/docker/Dockerfile.xgo @@ -1,4 +1,4 @@ -FROM karalabe/xgo-1.13.x +FROM techknowlogick/xgo:go-1.13.x WORKDIR /go/src/github.com/analogj/scrutiny From a4389b176df42ac854d33cd6394c5b82b7cac666 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 24 Oct 2021 22:09:57 -0700 Subject: [PATCH 035/114] we're already building windows binaries. Lets make sure we attach them as well. --- .github/workflows/build.yaml | 2 +- .github/workflows/release-windows.yaml | 43 -------------------------- .github/workflows/release.yaml | 2 +- 3 files changed, 2 insertions(+), 45 deletions(-) delete mode 100644 .github/workflows/release-windows.yaml diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 362aacc..0517459 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -6,7 +6,7 @@ jobs: build: name: Build runs-on: ubuntu-latest - container: karalabe/xgo-1.13.x + container: techknowlogick/xgo:go-1.13.x env: PROJECT_PATH: /go/src/github.com/analogj/scrutiny CGO_ENABLED: 1 diff --git a/.github/workflows/release-windows.yaml b/.github/workflows/release-windows.yaml deleted file mode 100644 index 6a675bd..0000000 --- a/.github/workflows/release-windows.yaml +++ /dev/null @@ -1,43 +0,0 @@ -# compiles Windows artifacts and attaches them to build -name: Release Windows - -on: - release: - # Only use the types keyword to narrow down the activity types that will trigger your workflow. - types: [published] - -jobs: - - release-windows: - name: Release Windows - runs-on: windows-latest - env: - GOOS: windows - GOARCH: amd64 - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - ref: ${{github.event.release.tag_name}} - - uses: actions/setup-go@v2 - with: - go-version: '^1.13.1' # The Go version to download (if necessary) and use. - - name: Build Binaries - shell: bash - run: | - mkdir -p $GITHUB_WORKSPACE/dist - - echo "building collector binary (OS = ${GOOS}, ARCH = ${GOARCH})" - go build -ldflags "-extldflags=-static -X main.goos=${GOOS} -X main.goarch=${GOARCH}" -o $GITHUB_WORKSPACE/dist/scrutiny-collector-metrics-${GOOS}-${GOARCH}.exe -tags "static netgo" collector/cmd/collector-metrics/collector-metrics.go - ls $GITHUB_WORKSPACE/dist/scrutiny-collector-metrics-${GOOS}-${GOARCH}.exe - - - name: Release Asset - Collector - windows-amd64 - id: upload-release-asset2 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ github.event.release.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: './dist/scrutiny-collector-metrics-windows-amd64.exe' - asset_name: scrutiny-collector-metrics-windows-amd64.exe - asset_content_type: application/octet-stream diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index cf26754..ba038ec 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -71,7 +71,7 @@ jobs: # This is necessary in order to push a commit to the repo GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} # Leave this line unchanged with: - upload_assets: '/build/scrutiny-web-linux-amd64 /build/scrutiny-collector-metrics-linux-amd64 /build/scrutiny-web-linux-arm64 /build/scrutiny-collector-metrics-linux-arm64 /build/scrutiny-web-linux-arm-5 /build/scrutiny-collector-metrics-linux-arm-5 /build/scrutiny-web-linux-arm-6 /build/scrutiny-collector-metrics-linux-arm-6 /build/scrutiny-web-linux-arm-7 /build/scrutiny-collector-metrics-linux-arm-7' + upload_assets: '/build/scrutiny-web-linux-amd64 /build/scrutiny-collector-metrics-linux-amd64 /build/scrutiny-web-linux-arm64 /build/scrutiny-collector-metrics-linux-arm64 /build/scrutiny-web-linux-arm-5 /build/scrutiny-collector-metrics-linux-arm-5 /build/scrutiny-web-linux-arm-6 /build/scrutiny-collector-metrics-linux-arm-6 /build/scrutiny-web-linux-arm-7 /build/scrutiny-collector-metrics-linux-arm-7 /build/scrutiny-web-windows-4.0-amd64.exe /build/scrutiny-collector-metrics-windows-4.0-amd64.exe' # - name: Release Asset - Web - linux-amd64 From e572c2051f40ded8201b59ef0b149f51a9457551 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 24 Oct 2021 22:22:58 -0700 Subject: [PATCH 036/114] specify metadata path --- .github/workflows/release.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ba038ec..11d65ee 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -71,6 +71,7 @@ jobs: # This is necessary in order to push a commit to the repo GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} # Leave this line unchanged with: + version_metadata_path: ${{ github.event.inputs.version_metadata_path }} upload_assets: '/build/scrutiny-web-linux-amd64 /build/scrutiny-collector-metrics-linux-amd64 /build/scrutiny-web-linux-arm64 /build/scrutiny-collector-metrics-linux-arm64 /build/scrutiny-web-linux-arm-5 /build/scrutiny-collector-metrics-linux-arm-5 /build/scrutiny-web-linux-arm-6 /build/scrutiny-collector-metrics-linux-arm-6 /build/scrutiny-web-linux-arm-7 /build/scrutiny-collector-metrics-linux-arm-7 /build/scrutiny-web-windows-4.0-amd64.exe /build/scrutiny-collector-metrics-windows-4.0-amd64.exe' From 3ee342763cf7f2fcd6085882bebf099160be8d39 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 24 Oct 2021 23:06:53 -0700 Subject: [PATCH 037/114] publish release using old mechanism. --- .github/workflows/release.yaml | 246 +++++++++++++++++++-------------- 1 file changed, 139 insertions(+), 107 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 11d65ee..352da1d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -64,119 +64,151 @@ jobs: GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} # Leave this line unchanged with: version_metadata_path: ${{ github.event.inputs.version_metadata_path }} - - name: Publish Release - id: publish - uses: packagrio/action-publishr-go@master +# - name: Publish Release +# id: publish +# uses: packagrio/action-publishr-go@master +# env: +# # This is necessary in order to push a commit to the repo +# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} # Leave this line unchanged +# with: +# version_metadata_path: ${{ github.event.inputs.version_metadata_path }} +# upload_assets: '/build/scrutiny-web-linux-amd64 /build/scrutiny-collector-metrics-linux-amd64 /build/scrutiny-web-linux-arm64 /build/scrutiny-collector-metrics-linux-arm64 /build/scrutiny-web-linux-arm-5 /build/scrutiny-collector-metrics-linux-arm-5 /build/scrutiny-web-linux-arm-6 /build/scrutiny-collector-metrics-linux-arm-6 /build/scrutiny-web-linux-arm-7 /build/scrutiny-collector-metrics-linux-arm-7 /build/scrutiny-web-windows-4.0-amd64.exe /build/scrutiny-collector-metrics-windows-4.0-amd64.exe' + + + - name: Create Release + id: create_release + uses: actions/create-release@v1 env: - # This is necessary in order to push a commit to the repo - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} # Leave this line unchanged + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} with: - version_metadata_path: ${{ github.event.inputs.version_metadata_path }} - upload_assets: '/build/scrutiny-web-linux-amd64 /build/scrutiny-collector-metrics-linux-amd64 /build/scrutiny-web-linux-arm64 /build/scrutiny-collector-metrics-linux-arm64 /build/scrutiny-web-linux-arm-5 /build/scrutiny-collector-metrics-linux-arm-5 /build/scrutiny-web-linux-arm-6 /build/scrutiny-collector-metrics-linux-arm-6 /build/scrutiny-web-linux-arm-7 /build/scrutiny-collector-metrics-linux-arm-7 /build/scrutiny-web-windows-4.0-amd64.exe /build/scrutiny-collector-metrics-windows-4.0-amd64.exe' + tag_name: ${{ steps.bump_version.outputs.release_version }} + release_name: Release ${{ steps.bump_version.outputs.release_version }} + draft: false + prerelease: false + - name: Release Asset - Web - linux-amd64 + id: upload-release-asset1 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-web-linux-amd64 + asset_name: scrutiny-web-linux-amd64 + asset_content_type: application/octet-stream + - name: Release Asset - Collector - linux-amd64 + id: upload-release-asset2 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-collector-metrics-linux-amd64 + asset_name: scrutiny-collector-metrics-linux-amd64 + asset_content_type: application/octet-stream -# - name: Release Asset - Web - linux-amd64 -# id: upload-release-asset1 -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: /build/scrutiny-web-linux-amd64 -# asset_name: scrutiny-web-linux-amd64 -# asset_content_type: application/octet-stream -# - name: Release Asset - Collector - linux-amd64 -# id: upload-release-asset2 -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: /build/scrutiny-collector-metrics-linux-amd64 -# asset_name: scrutiny-collector-metrics-linux-amd64 -# asset_content_type: application/octet-stream + - name: Release Asset - Web - linux-arm64 + id: upload-release-asset3 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-web-linux-arm64 + asset_name: scrutiny-web-linux-arm64 + asset_content_type: application/octet-stream + - name: Release Asset - Collector - linux-arm64 + id: upload-release-asset4 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-collector-metrics-linux-arm64 + asset_name: scrutiny-collector-metrics-linux-arm64 + asset_content_type: application/octet-stream -# - name: Release Asset - Web - linux-arm64 -# id: upload-release-asset3 -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: /build/scrutiny-web-linux-arm64 -# asset_name: scrutiny-web-linux-arm64 -# asset_content_type: application/octet-stream -# - name: Release Asset - Collector - linux-arm64 -# id: upload-release-asset4 -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: /build/scrutiny-collector-metrics-linux-arm64 -# asset_name: scrutiny-collector-metrics-linux-arm64 -# asset_content_type: application/octet-stream + - name: Release Asset - Web - linux-arm-5 + id: upload-release-asset5 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-web-linux-arm-5 + asset_name: scrutiny-web-linux-arm-5 + asset_content_type: application/octet-stream + - name: Release Asset - Collector - linux-arm-5 + id: upload-release-asset6 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-collector-metrics-linux-arm-5 + asset_name: scrutiny-collector-metrics-linux-arm-5 + asset_content_type: application/octet-stream -# - name: Release Asset - Web - linux-arm-5 -# id: upload-release-asset5 -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: /build/scrutiny-web-linux-arm-5 -# asset_name: scrutiny-web-linux-arm-5 -# asset_content_type: application/octet-stream -# - name: Release Asset - Collector - linux-arm-5 -# id: upload-release-asset6 -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: /build/scrutiny-collector-metrics-linux-arm-5 -# asset_name: scrutiny-collector-metrics-linux-arm-5 -# asset_content_type: application/octet-stream + - name: Release Asset - Web - linux-arm-6 + id: upload-release-asset7 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-web-linux-arm-6 + asset_name: scrutiny-web-linux-arm-6 + asset_content_type: application/octet-stream + - name: Release Asset - Collector - linux-arm-6 + id: upload-release-asset8 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-collector-metrics-linux-arm-6 + asset_name: scrutiny-collector-metrics-linux-arm-6 + asset_content_type: application/octet-stream -# - name: Release Asset - Web - linux-arm-6 -# id: upload-release-asset7 -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: /build/scrutiny-web-linux-arm-6 -# asset_name: scrutiny-web-linux-arm-6 -# asset_content_type: application/octet-stream -# - name: Release Asset - Collector - linux-arm-6 -# id: upload-release-asset8 -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: /build/scrutiny-collector-metrics-linux-arm-6 -# asset_name: scrutiny-collector-metrics-linux-arm-6 -# asset_content_type: application/octet-stream + - name: Release Asset - Web - linux-arm-7 + id: upload-release-asset9 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-web-linux-arm-7 + asset_name: scrutiny-web-linux-arm-7 + asset_content_type: application/octet-stream + - name: Release Asset - Collector - linux-arm-7 + id: upload-release-asset10 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-collector-metrics-linux-arm-7 + asset_name: scrutiny-collector-metrics-linux-arm-7 + asset_content_type: application/octet-stream -# - name: Release Asset - Web - linux-arm-7 -# id: upload-release-asset9 -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: /build/scrutiny-web-linux-arm-7 -# asset_name: scrutiny-web-linux-arm-7 -# asset_content_type: application/octet-stream -# - name: Release Asset - Collector - linux-arm-7 -# id: upload-release-asset10 -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: /build/scrutiny-collector-metrics-linux-arm-7 -# asset_name: scrutiny-collector-metrics-linux-arm-7 -# asset_content_type: application/octet-stream + - name: Release Asset - Web - windows-amd64 + id: upload-release-asset11 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-web-windows-4.0-amd64.exe + asset_name: scrutiny-web-windows-4.0-amd64.exe + asset_content_type: application/octet-stream + - name: Release Asset - Collector - windows-amd64 + id: upload-release-asset12 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-collector-metrics-windows-4.0-amd64.exe + asset_name: scrutiny-collector-metrics-windows-4.0-amd64.exe + asset_content_type: application/octet-stream From 060ac7b83a7525c99bf2f03c26dcb3d89dafc976 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Mon, 25 Oct 2021 21:03:06 -0700 Subject: [PATCH 038/114] fixes https://github.com/AnalogJ/scrutiny/issues/179 --- webapp/backend/pkg/notify/notify.go | 1 - 1 file changed, 1 deletion(-) diff --git a/webapp/backend/pkg/notify/notify.go b/webapp/backend/pkg/notify/notify.go index da771a5..5b81464 100644 --- a/webapp/backend/pkg/notify/notify.go +++ b/webapp/backend/pkg/notify/notify.go @@ -258,7 +258,6 @@ func (n *Notify) GenShoutrrrNotificationParams(shoutrrrUrl string) (string, *sho (*params)["title"] = subject case "slack": (*params)["title"] = subject - (*params)["thumb_url"] = logoUrl case "smtp": (*params)["subject"] = subject case "standard": From ce032c56097de4de6a84e87e534877d6be6c8693 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Thu, 28 Oct 2021 07:35:25 -0700 Subject: [PATCH 039/114] fixes for Scrutiny end-to-end testing. --- .../pkg/database/scrutiny_repository.go | 6 + webapp/backend/pkg/models/device_summary.go | 8 ++ webapp/backend/pkg/web/server_test.go | 133 +++++++++++++++--- 3 files changed, 129 insertions(+), 18 deletions(-) diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index 0ff4a36..92fba10 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -590,6 +590,12 @@ func (sr *scrutinyRepository) GetSummary(ctx context.Context) (map[string]*model //get summary data from Influxdb. //result.Record().Values() if deviceWWN, ok := result.Record().Values()["device_wwn"]; ok { + + //ensure summaries is intialized for this wwn + if _, exists := summaries[deviceWWN.(string)]; !exists { + summaries[deviceWWN.(string)] = &models.DeviceSummary{} + } + summaries[deviceWWN.(string)].SmartResults = &models.SmartSummary{ Temp: result.Record().Values()["temp"].(int64), PowerOnHours: result.Record().Values()["power_on_hours"].(int64), diff --git a/webapp/backend/pkg/models/device_summary.go b/webapp/backend/pkg/models/device_summary.go index c1781e3..f4ca323 100644 --- a/webapp/backend/pkg/models/device_summary.go +++ b/webapp/backend/pkg/models/device_summary.go @@ -5,6 +5,14 @@ import ( "time" ) +type DeviceSummaryWrapper struct { + Success bool `json:"success"` + Errors []error `json:"errors"` + Data struct { + Summary map[string]*DeviceSummary `json:"summary"` + } `json:"data"` +} + type DeviceSummary struct { Device Device `json:"device"` diff --git a/webapp/backend/pkg/web/server_test.go b/webapp/backend/pkg/web/server_test.go index 8f4a672..b70a31c 100644 --- a/webapp/backend/pkg/web/server_test.go +++ b/webapp/backend/pkg/web/server_test.go @@ -1,14 +1,17 @@ package web_test import ( + "bytes" "encoding/json" "github.com/analogj/scrutiny/webapp/backend/pkg" mock_config "github.com/analogj/scrutiny/webapp/backend/pkg/config/mock" "github.com/analogj/scrutiny/webapp/backend/pkg/models" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" "github.com/analogj/scrutiny/webapp/backend/pkg/web" "github.com/golang/mock/gomock" "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" + "io" "io/ioutil" "net/http" "net/http/httptest" @@ -16,8 +19,48 @@ import ( "path" "strings" "testing" + "time" ) +/* +All tests in this file require the existance of a influxDB listening on port 8086 + +docker run --rm -it -p 8086:8086 \ +-e DOCKER_INFLUXDB_INIT_MODE=setup \ +-e DOCKER_INFLUXDB_INIT_USERNAME=admin \ +-e DOCKER_INFLUXDB_INIT_PASSWORD=password12345 \ +-e DOCKER_INFLUXDB_INIT_ORG=scrutiny \ +-e DOCKER_INFLUXDB_INIT_BUCKET=metrics \ +-e DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=my-super-secret-auth-token \ +influxdb:2.0 +*/ + +//func TestMain(m *testing.M) { +// setup() +// code := m.Run() +// shutdown() +// os.Exit(code) +//} + +// InfluxDB will throw an error/ignore any submitted data with a timestamp older than the +// retention period. Lets fix this by opening test files, modifying the timestamp and returning an io.Reader +func helperReadSmartDataFileFixTimestamp(t *testing.T, smartDataFilepath string) io.Reader { + metricsfile, err := os.Open(smartDataFilepath) + require.NoError(t, err) + + metricsFileData, err := ioutil.ReadAll(metricsfile) + require.NoError(t, err) + + //unmarshal because we need to change the timestamp + var smartData collector.SmartInfo + err = json.Unmarshal(metricsFileData, &smartData) + require.NoError(t, err) + smartData.LocalTime.TimeT = time.Now().Unix() + updatedSmartDataBytes, err := json.Marshal(smartData) + + return bytes.NewReader(updatedSmartDataBytes) +} + func TestHealthRoute(t *testing.T) { //setup parentPath, _ := ioutil.TempDir("", "") @@ -27,6 +70,12 @@ func TestHealthRoute(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").Return(path.Join(parentPath, "scrutiny_test.db")).AnyTimes() fakeConfig.EXPECT().GetString("web.src.frontend.path").Return(parentPath).AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() + fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() ae := web.AppEngine{ Config: fakeConfig, @@ -53,6 +102,13 @@ func TestRegisterDevicesRoute(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").Return(path.Join(parentPath, "scrutiny_test.db")).AnyTimes() fakeConfig.EXPECT().GetString("web.src.frontend.path").Return(parentPath).AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() + fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() + ae := web.AppEngine{ Config: fakeConfig, } @@ -78,6 +134,13 @@ func TestUploadDeviceMetricsRoute(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() + fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() + ae := web.AppEngine{ Config: fakeConfig, } @@ -85,8 +148,7 @@ func TestUploadDeviceMetricsRoute(t *testing.T) { devicesfile, err := os.Open("testdata/register-devices-single-req.json") require.NoError(t, err) - metricsfile, err := os.Open("testdata/upload-device-metrics-req.json") - require.NoError(t, err) + metricsfile := helperReadSmartDataFileFixTimestamp(t, "testdata/upload-device-metrics-req.json") //test wr := httptest.NewRecorder() @@ -113,6 +175,13 @@ func TestPopulateMultiple(t *testing.T) { fakeConfig.EXPECT().GetStringSlice("notify.urls").Return([]string{}).AnyTimes() fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() + fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() + ae := web.AppEngine{ Config: fakeConfig, } @@ -120,16 +189,11 @@ func TestPopulateMultiple(t *testing.T) { devicesfile, err := os.Open("testdata/register-devices-req.json") require.NoError(t, err) - metricsfile, err := os.Open("../models/testdata/smart-ata.json") - require.NoError(t, err) - failfile, err := os.Open("../models/testdata/smart-fail2.json") - require.NoError(t, err) - nvmefile, err := os.Open("../models/testdata/smart-nvme.json") - require.NoError(t, err) - scsifile, err := os.Open("../models/testdata/smart-scsi.json") - require.NoError(t, err) - scsi2file, err := os.Open("../models/testdata/smart-scsi2.json") - require.NoError(t, err) + metricsfile := helperReadSmartDataFileFixTimestamp(t, "../models/testdata/smart-ata.json") + failfile := helperReadSmartDataFileFixTimestamp(t, "../models/testdata/smart-fail2.json") + nvmefile := helperReadSmartDataFileFixTimestamp(t, "../models/testdata/smart-nvme.json") + scsifile := helperReadSmartDataFileFixTimestamp(t, "../models/testdata/smart-scsi.json") + scsi2file := helperReadSmartDataFileFixTimestamp(t, "../models/testdata/smart-scsi2.json") //test wr := httptest.NewRecorder() @@ -199,6 +263,12 @@ func TestSendTestNotificationRoute_WebhookFailure(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() + fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"https://unroutable.domain.example.asdfghj"}) ae := web.AppEngine{ Config: fakeConfig, @@ -223,6 +293,12 @@ func TestSendTestNotificationRoute_ScriptFailure(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() + fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"script:///missing/path/on/disk"}) ae := web.AppEngine{ Config: fakeConfig, @@ -247,6 +323,13 @@ func TestSendTestNotificationRoute_ScriptSuccess(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() + fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() + fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"script:///usr/bin/env"}) ae := web.AppEngine{ Config: fakeConfig, @@ -271,6 +354,12 @@ func TestSendTestNotificationRoute_ShoutrrrFailure(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() + fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"discord://invalidtoken@channel"}) ae := web.AppEngine{ Config: fakeConfig, @@ -295,6 +384,14 @@ func TestGetDevicesSummaryRoute_Nvme(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() + fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() + fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{}) + ae := web.AppEngine{ Config: fakeConfig, } @@ -302,8 +399,7 @@ func TestGetDevicesSummaryRoute_Nvme(t *testing.T) { devicesfile, err := os.Open("testdata/register-devices-req-2.json") require.NoError(t, err) - metricsfile, err := os.Open("../models/testdata/smart-nvme2.json") - require.NoError(t, err) + metricsfile := helperReadSmartDataFileFixTimestamp(t, "../models/testdata/smart-nvme2.json") //test wr := httptest.NewRecorder() @@ -320,10 +416,11 @@ func TestGetDevicesSummaryRoute_Nvme(t *testing.T) { req, _ = http.NewRequest("GET", "/api/summary", nil) router.ServeHTTP(sr, req) require.Equal(t, 200, sr.Code) - var device models.DeviceWrapper - json.Unmarshal(sr.Body.Bytes(), &device) + var deviceSummary models.DeviceSummaryWrapper + err = json.Unmarshal(sr.Body.Bytes(), &deviceSummary) + require.NoError(t, err) //assert - require.Equal(t, "a4c8e8ed-11a0-4c97-9bba-306440f1b944", device.Data[0].WWN) - require.Equal(t, pkg.DeviceStatusPassed, device.Data[0].DeviceStatus) + require.Equal(t, "a4c8e8ed-11a0-4c97-9bba-306440f1b944", deviceSummary.Data.Summary["a4c8e8ed-11a0-4c97-9bba-306440f1b944"].Device.WWN) + require.Equal(t, pkg.DeviceStatusFailedScrutiny, deviceSummary.Data.Summary["a4c8e8ed-11a0-4c97-9bba-306440f1b944"].Device.DeviceStatus) } From 8fb58591a6e34094eae26e32949f7d0ab7177c82 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Thu, 28 Oct 2021 07:41:41 -0700 Subject: [PATCH 040/114] fixes for Scrutiny end-to-end testing. --- .github/workflows/build.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 362aacc..14ad185 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -7,6 +7,20 @@ jobs: name: Build runs-on: ubuntu-latest container: karalabe/xgo-1.13.x + + # Service containers to run with `build` (Required for end-to-end testing) + services: + influxdb: + image: influxdb:2.0 + env: + DOCKER_INFLUXDB_INIT_MODE: setup + DOCKER_INFLUXDB_INIT_USERNAME: admin + DOCKER_INFLUXDB_INIT_PASSWORD: password12345 + DOCKER_INFLUXDB_INIT_ORG: scrutiny + DOCKER_INFLUXDB_INIT_BUCKET: metrics + DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: my-super-secret-auth-token + ports: + - 8086:8086 env: PROJECT_PATH: /go/src/github.com/analogj/scrutiny CGO_ENABLED: 1 From b776fb888618ae6e86953bf5e314cbaeee108b34 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Tue, 16 Nov 2021 18:32:29 -0800 Subject: [PATCH 041/114] tweaking retention policy code so we can test downsampling scripts. --- CONTRIBUTING.md | 23 +- example.scrutiny.yaml | 1 + webapp/backend/pkg/config/config.go | 1 + .../pkg/database/scrutiny_repository.go | 40 +- webapp/backend/pkg/models/testdata/helper.go | 97 ++ .../pkg/models/testdata/smart-ata-date.json | 2 +- .../pkg/models/testdata/smart-ata-date2.json | 2 +- .../pkg/models/testdata/smart-ata-full.json | 2 +- .../pkg/models/testdata/smart-ata.json | 2 +- .../pkg/models/testdata/smart-ata2.json | 2 +- .../pkg/models/testdata/smart-fail2.json | 2 +- .../pkg/models/testdata/smart-megaraid0.json | 2 +- .../pkg/models/testdata/smart-megaraid1.json | 2 +- .../pkg/models/testdata/smart-nvme.json | 2 +- .../pkg/models/testdata/smart-nvme2.json | 2 +- .../pkg/models/testdata/smart-raid.json | 2 +- .../pkg/models/testdata/smart-scsi.json | 2 +- .../pkg/models/testdata/smart-scsi2.json | 2 +- webapp/frontend/package-lock.json | 888 ++++++++++++------ 19 files changed, 730 insertions(+), 346 deletions(-) create mode 100644 webapp/backend/pkg/models/testdata/helper.go diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 48f0cb6..c184ef2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -54,7 +54,8 @@ web: src: frontend: path: ./dist - + influxdb: + retention_policy: false log: file: 'web.log' #absolute or relative paths allowed, eg. web.log @@ -80,7 +81,7 @@ If you'd like to populate the database with some test data, you can run the fol docker run -p 8086:8086 --rm influxdb:2.0 -docker run -p 8086:8086 \ +docker run --rm -p 8086:8086 \ -e DOCKER_INFLUXDB_INIT_USERNAME=admin \ -e DOCKER_INFLUXDB_INIT_PASSWORD=password12345 \ -e DOCKER_INFLUXDB_INIT_ORG=scrutiny \ @@ -88,15 +89,15 @@ docker run -p 8086:8086 \ influxdb:2.0 -curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/web/testdata/register-devices-req.json localhost:8080/api/devices/register - -curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-ata.json localhost:8080/api/device/0x5000cca264eb01d7/smart -curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-ata-date.json localhost:8080/api/device/0x5000cca264eb01d7/smart -curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-ata-date2.json localhost:8080/api/device/0x5000cca264eb01d7/smart -curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-fail2.json localhost:8080/api/device/0x5000cca264ec3183/smart -curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-nvme.json localhost:8080/api/device/0x5002538e40a22954/smart -curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-scsi.json localhost:8080/api/device/0x5000cca252c859cc/smart -curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-scsi2.json localhost:8080/api/device/0x5000cca264ebc248/smart +# curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/web/testdata/register-devices-req.json localhost:8080/api/devices/register +# curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-ata.json localhost:8080/api/device/0x5000cca264eb01d7/smart +# curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-ata-date.json localhost:8080/api/device/0x5000cca264eb01d7/smart +# curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-ata-date2.json localhost:8080/api/device/0x5000cca264eb01d7/smart +# curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-fail2.json localhost:8080/api/device/0x5000cca264ec3183/smart +# curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-nvme.json localhost:8080/api/device/0x5002538e40a22954/smart +# curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-scsi.json localhost:8080/api/device/0x5000cca252c859cc/smart +# curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/models/testdata/smart-scsi2.json localhost:8080/api/device/0x5000cca264ebc248/smart +go run webapp/backend/pkg/models/testdata/helper.go curl localhost:8080/api/summary diff --git a/example.scrutiny.yaml b/example.scrutiny.yaml index f7460ed..2fbe455 100644 --- a/example.scrutiny.yaml +++ b/example.scrutiny.yaml @@ -32,6 +32,7 @@ web: # token: 'my-token' # org: 'my-org' # bucket: 'bucket' + retention_policy: true log: file: '' #absolute or relative paths allowed, eg. web.log diff --git a/webapp/backend/pkg/config/config.go b/webapp/backend/pkg/config/config.go index beccb90..27e1c05 100644 --- a/webapp/backend/pkg/config/config.go +++ b/webapp/backend/pkg/config/config.go @@ -43,6 +43,7 @@ func (c *configuration) Init() error { c.SetDefault("web.influxdb.bucket", "metrics") c.SetDefault("web.influxdb.init_username", "admin") c.SetDefault("web.influxdb.init_password", "password12345") + c.SetDefault("web.influxdb.retention_policy", true) //c.SetDefault("disks.include", []string{}) //c.SetDefault("disks.exclude", []string{}) diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index 92fba10..530348b 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -18,6 +18,17 @@ import ( "time" ) +const ( + // 60seconds * 60minutes * 24hours * 15 days + RETENTION_PERIOD_15_DAYS_IN_SECONDS = 1_296_000 + + // 60seconds * 60minutes * 24hours * 7 days * 9 weeks + RETENTION_PERIOD_9_WEEKS_IN_SECONDS = 5_443_200 + + // 60seconds * 60minutes * 24hours * 7 days * (52 + 52 + 4)weeks + RETENTION_PERIOD_25_MONTHS_IN_SECONDS = 65_318_400 +) + //// GormLogger is a custom logger for Gorm, making it use logrus. //type GormLogger struct{ Logger logrus.FieldLogger } // @@ -151,17 +162,28 @@ func (sr *scrutinyRepository) Close() error { func (sr *scrutinyRepository) EnsureBuckets(ctx context.Context, org *domain.Organization) error { + var mainBucketRetentionRule domain.RetentionRule + var weeklyBucketRetentionRule domain.RetentionRule + var monthlyBucketRetentionRule domain.RetentionRule + if sr.appConfig.GetBool("web.influxdb.retention_policy") { + + // for tetsting purposes, we may not want to set a retention policy, this will allow to set data with old timestamps, + //then manually run the downsampling scripts + mainBucketRetentionRule = domain.RetentionRule{EverySeconds: RETENTION_PERIOD_15_DAYS_IN_SECONDS} + weeklyBucketRetentionRule = domain.RetentionRule{EverySeconds: RETENTION_PERIOD_9_WEEKS_IN_SECONDS} + monthlyBucketRetentionRule = domain.RetentionRule{EverySeconds: RETENTION_PERIOD_25_MONTHS_IN_SECONDS} + } + mainBucket := sr.appConfig.GetString("web.influxdb.bucket") if foundMainBucket, foundErr := sr.influxClient.BucketsAPI().FindBucketByName(ctx, mainBucket); foundErr != nil { - // metrics bucket will have a retention period of (14+1) 15 days (since it will be down-sampled once a week) - // in seconds (60seconds * 60minutes * 24hours * 15 days) = 1_296_000 - _, err := sr.influxClient.BucketsAPI().CreateBucketWithName(ctx, org, mainBucket, domain.RetentionRule{EverySeconds: 1_296_000}) + // metrics bucket will have a retention period of 15 days (since it will be down-sampled once a week) + _, err := sr.influxClient.BucketsAPI().CreateBucketWithName(ctx, org, mainBucket, mainBucketRetentionRule) if err != nil { return err } - } else { - //correctly set the retention period for the main bucket (cant do it during creation) - foundMainBucket.RetentionRules = domain.RetentionRules{domain.RetentionRule{EverySeconds: 1_296_000}} + } else if sr.appConfig.GetBool("web.influxdb.retention_policy") { + //correctly set the retention period for the main bucket (cant do it during setup/creation) + foundMainBucket.RetentionRules = domain.RetentionRules{mainBucketRetentionRule} sr.influxClient.BucketsAPI().UpdateBucket(ctx, foundMainBucket) } @@ -169,8 +191,7 @@ func (sr *scrutinyRepository) EnsureBuckets(ctx context.Context, org *domain.Org weeklyBucket := fmt.Sprintf("%s_weekly", sr.appConfig.GetString("web.influxdb.bucket")) if _, foundErr := sr.influxClient.BucketsAPI().FindBucketByName(ctx, weeklyBucket); foundErr != nil { // metrics_weekly bucket will have a retention period of 8+1 weeks (since it will be down-sampled once a month) - // in seconds (60seconds * 60minutes * 24hours * 7 days * 9 weeks) = 5_443_200 - _, err := sr.influxClient.BucketsAPI().CreateBucketWithName(ctx, org, weeklyBucket, domain.RetentionRule{EverySeconds: 5_443_200}) + _, err := sr.influxClient.BucketsAPI().CreateBucketWithName(ctx, org, weeklyBucket, weeklyBucketRetentionRule) if err != nil { return err } @@ -179,8 +200,7 @@ func (sr *scrutinyRepository) EnsureBuckets(ctx context.Context, org *domain.Org monthlyBucket := fmt.Sprintf("%s_monthly", sr.appConfig.GetString("web.influxdb.bucket")) if _, foundErr := sr.influxClient.BucketsAPI().FindBucketByName(ctx, monthlyBucket); foundErr != nil { // metrics_monthly bucket will have a retention period of 24+1 months (since it will be down-sampled once a year) - // in seconds (60seconds * 60minutes * 24hours * 7 days * (52 + 52 + 4)weeks) = 65_318_400 - _, err := sr.influxClient.BucketsAPI().CreateBucketWithName(ctx, org, monthlyBucket, domain.RetentionRule{EverySeconds: 65_318_400}) + _, err := sr.influxClient.BucketsAPI().CreateBucketWithName(ctx, org, monthlyBucket, monthlyBucketRetentionRule) if err != nil { return err } diff --git a/webapp/backend/pkg/models/testdata/helper.go b/webapp/backend/pkg/models/testdata/helper.go new file mode 100644 index 0000000..559829c --- /dev/null +++ b/webapp/backend/pkg/models/testdata/helper.go @@ -0,0 +1,97 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" + "io" + "io/ioutil" + "log" + "net/http" + "os" + "time" +) + +func main() { + + //webapp/backend/pkg/web/testdata/register-devices-req.json + devices := "webapp/backend/pkg/web/testdata/register-devices-req.json" + + smartData := map[string][]string{ + "0x5000cca264eb01d7": {"webapp/backend/pkg/models/testdata/smart-ata.json", "webapp/backend/pkg/models/testdata/smart-ata-date.json", "webapp/backend/pkg/models/testdata/smart-ata-date2.json"}, + "0x5000cca264ec3183": {"webapp/backend/pkg/models/testdata/smart-fail2.json"}, + "0x5002538e40a22954": {"webapp/backend/pkg/models/testdata/smart-nvme.json"}, + "0x5000cca252c859cc": {"webapp/backend/pkg/models/testdata/smart-scsi.json"}, + "0x5000cca264ebc248": {"webapp/backend/pkg/models/testdata/smart-scsi2.json"}, + } + + // send a post request to register devices + file, err := os.Open(devices) + if err != nil { + log.Fatalf("ERROR %v", err) + } + defer file.Close() + _, err = SendPostRequest("http://localhost:8080/api/devices/register", file) + if err != nil { + log.Fatalf("ERROR %v", err) + } + // + + for diskId, smartDataFileNames := range smartData { + for _, smartDataFileName := range smartDataFileNames { + for daysToSubtract := 0; daysToSubtract <= 30; daysToSubtract++ { //add 4 weeks worth of data + smartDataReader, err := readSmartDataFileFixTimestamp(daysToSubtract, smartDataFileName) + if err != nil { + log.Fatalf("ERROR %v", err) + } + + _, err = SendPostRequest(fmt.Sprintf("http://localhost:8080/api/device/%s/smart", diskId), smartDataReader) + if err != nil { + log.Fatalf("ERROR %v", err) + } + } + + } + + } + +} + +func SendPostRequest(url string, file io.Reader) ([]byte, error) { + response, err := http.Post(url, "application/json", file) + if err != nil { + return nil, err + } + defer response.Body.Close() + + log.Printf("%v\n", response.Status) + + return ioutil.ReadAll(response.Body) +} + +// InfluxDB will throw an error/ignore any submitted data with a timestamp older than the +// retention period. Lets fix this by opening test files, modifying the timestamp and returning an io.Reader +func readSmartDataFileFixTimestamp(daysToSubtract int, smartDataFilepath string) (io.Reader, error) { + metricsfile, err := os.Open(smartDataFilepath) + if err != nil { + return nil, err + } + + metricsFileData, err := ioutil.ReadAll(metricsfile) + if err != nil { + return nil, err + } + //unmarshal because we need to change the timestamp + var smartData collector.SmartInfo + err = json.Unmarshal(metricsFileData, &smartData) + if err != nil { + return nil, err + } + + daysToSubtractInHours := time.Duration(-1 * 24 * daysToSubtract) + smartData.LocalTime.TimeT = time.Now().Add(daysToSubtractInHours * time.Hour).Unix() + updatedSmartDataBytes, err := json.Marshal(smartData) + + return bytes.NewReader(updatedSmartDataBytes), nil +} diff --git a/webapp/backend/pkg/models/testdata/smart-ata-date.json b/webapp/backend/pkg/models/testdata/smart-ata-date.json index 92c9382..4e9cf35 100644 --- a/webapp/backend/pkg/models/testdata/smart-ata-date.json +++ b/webapp/backend/pkg/models/testdata/smart-ata-date.json @@ -69,7 +69,7 @@ } }, "local_time": { - "time_t": 1635107644, + "time_t": 1637039918, "asctime": "Sun Jun 30 00:03:30 2021 UTC" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-ata-date2.json b/webapp/backend/pkg/models/testdata/smart-ata-date2.json index 3cced16..5c64623 100644 --- a/webapp/backend/pkg/models/testdata/smart-ata-date2.json +++ b/webapp/backend/pkg/models/testdata/smart-ata-date2.json @@ -69,7 +69,7 @@ } }, "local_time": { - "time_t": 1635127644, + "time_t": 1637039918, "asctime": "Tue Feb 23 00:03:30 2021 UTC" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-ata-full.json b/webapp/backend/pkg/models/testdata/smart-ata-full.json index bf7a3d5..ad2c195 100644 --- a/webapp/backend/pkg/models/testdata/smart-ata-full.json +++ b/webapp/backend/pkg/models/testdata/smart-ata-full.json @@ -70,7 +70,7 @@ } }, "local_time": { - "time_t": 1635117644, + "time_t": 1637039918, "asctime": "Sun Sep 13 16:29:23 2020 UTC" }, "read_lookahead": { diff --git a/webapp/backend/pkg/models/testdata/smart-ata.json b/webapp/backend/pkg/models/testdata/smart-ata.json index 421fed6..eebe241 100644 --- a/webapp/backend/pkg/models/testdata/smart-ata.json +++ b/webapp/backend/pkg/models/testdata/smart-ata.json @@ -69,7 +69,7 @@ } }, "local_time": { - "time_t": 1635117644, + "time_t": 1637039918, "asctime": "Sun Jun 21 00:03:30 2020 UTC" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-ata2.json b/webapp/backend/pkg/models/testdata/smart-ata2.json index 4480c55..9b03cfd 100644 --- a/webapp/backend/pkg/models/testdata/smart-ata2.json +++ b/webapp/backend/pkg/models/testdata/smart-ata2.json @@ -66,7 +66,7 @@ } }, "local_time": { - "time_t": 1635117644, + "time_t": 1637039918, "asctime": "Thu Aug 01 15:05:13 2019 WEDT" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-fail2.json b/webapp/backend/pkg/models/testdata/smart-fail2.json index e7571e6..fe10e17 100644 --- a/webapp/backend/pkg/models/testdata/smart-fail2.json +++ b/webapp/backend/pkg/models/testdata/smart-fail2.json @@ -70,7 +70,7 @@ } }, "local_time": { - "time_t": 1635117644, + "time_t": 1637039918, "asctime": "Wed Jul 8 15:48:23 2020 CEST" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-megaraid0.json b/webapp/backend/pkg/models/testdata/smart-megaraid0.json index 9f51c62..a848330 100644 --- a/webapp/backend/pkg/models/testdata/smart-megaraid0.json +++ b/webapp/backend/pkg/models/testdata/smart-megaraid0.json @@ -79,7 +79,7 @@ } }, "local_time": { - "time_t": 1635117644, + "time_t": 1637039918, "asctime": "Mon Aug 24 21:38:38 2020 CEST" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-megaraid1.json b/webapp/backend/pkg/models/testdata/smart-megaraid1.json index 4a0043a..958a86a 100644 --- a/webapp/backend/pkg/models/testdata/smart-megaraid1.json +++ b/webapp/backend/pkg/models/testdata/smart-megaraid1.json @@ -79,7 +79,7 @@ } }, "local_time": { - "time_t": 1635117644, + "time_t": 1637039918, "asctime": "Mon Aug 24 21:38:42 2020 CEST" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-nvme.json b/webapp/backend/pkg/models/testdata/smart-nvme.json index 232e88f..07937e8 100644 --- a/webapp/backend/pkg/models/testdata/smart-nvme.json +++ b/webapp/backend/pkg/models/testdata/smart-nvme.json @@ -59,7 +59,7 @@ }, "logical_block_size": 512, "local_time": { - "time_t": 1635117644, + "time_t": 1637039918, "asctime": "Wed Jun 10 14:01:02 2020 CEST" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-nvme2.json b/webapp/backend/pkg/models/testdata/smart-nvme2.json index 5d03273..8b96836 100644 --- a/webapp/backend/pkg/models/testdata/smart-nvme2.json +++ b/webapp/backend/pkg/models/testdata/smart-nvme2.json @@ -67,7 +67,7 @@ }, "logical_block_size": 512, "local_time": { - "time_t": 1635117644, + "time_t": 1637039918, "asctime": "Sun Sep 20 16:24:50 2020 Europe" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-raid.json b/webapp/backend/pkg/models/testdata/smart-raid.json index 364285c..9fb882f 100644 --- a/webapp/backend/pkg/models/testdata/smart-raid.json +++ b/webapp/backend/pkg/models/testdata/smart-raid.json @@ -43,7 +43,7 @@ "name": "disk" }, "local_time": { - "time_t": 1635117644, + "time_t": 1637039918, "asctime": "Wed Oct 09 10:31:07 2019 RDT" }, "temperature": { diff --git a/webapp/backend/pkg/models/testdata/smart-scsi.json b/webapp/backend/pkg/models/testdata/smart-scsi.json index 0b12720..59cd479 100644 --- a/webapp/backend/pkg/models/testdata/smart-scsi.json +++ b/webapp/backend/pkg/models/testdata/smart-scsi.json @@ -26,7 +26,7 @@ "name": "disk" }, "local_time": { - "time_t": 1635117644, + "time_t": 1637039918, "asctime": "Fri Aug 21 22:27:02 2020 UTC" }, "smart_status": { diff --git a/webapp/backend/pkg/models/testdata/smart-scsi2.json b/webapp/backend/pkg/models/testdata/smart-scsi2.json index 0995356..2cd7601 100644 --- a/webapp/backend/pkg/models/testdata/smart-scsi2.json +++ b/webapp/backend/pkg/models/testdata/smart-scsi2.json @@ -44,7 +44,7 @@ "name": "disk" }, "local_time": { - "time_t": 1635117644, + "time_t": 1637039918, "asctime": "Sun Dec 16 17:09:15 2018 CST" }, "smart_status": { diff --git a/webapp/frontend/package-lock.json b/webapp/frontend/package-lock.json index 1e3751f..cae08a9 100644 --- a/webapp/frontend/package-lock.json +++ b/webapp/frontend/package-lock.json @@ -15984,30 +15984,34 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/abbrev": { "version": "1.1.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/ansi-regex": { "version": "2.1.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/aproba": { "version": "1.2.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/are-we-there-yet": { "version": "1.1.5", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -16015,15 +16019,17 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/balanced-match": { "version": "1.0.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/brace-expansion": { "version": "1.1.11", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -16031,66 +16037,75 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/chownr": { "version": "1.1.4", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/code-point-at": { "version": "1.1.0", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/concat-map": { "version": "0.0.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/console-control-strings": { "version": "1.1.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/core-util-is": { "version": "1.0.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/debug": { "version": "3.2.6", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "ms": "^2.1.1" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/deep-extend": { "version": "0.6.0", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=4.0.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/delegates": { "version": "1.0.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/detect-libc": { "version": "1.0.3", - "extraneous": true, + "dev": true, "inBundle": true, "license": "Apache-2.0", + "optional": true, "bin": { "detect-libc": "bin/detect-libc.js" }, @@ -16100,24 +16115,27 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/fs-minipass": { "version": "1.2.7", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "minipass": "^2.6.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/fs.realpath": { "version": "1.0.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/gauge": { "version": "2.7.4", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -16131,9 +16149,10 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/glob": { "version": "7.1.6", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -16151,15 +16170,17 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/has-unicode": { "version": "2.0.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/iconv-lite": { "version": "0.4.24", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -16169,18 +16190,20 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/ignore-walk": { "version": "3.0.3", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "minimatch": "^3.0.4" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/inflight": { "version": "1.0.6", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -16188,24 +16211,27 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/inherits": { "version": "2.0.4", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/ini": { "version": "1.3.5", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "engines": { "node": "*" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/is-fullwidth-code-point": { "version": "1.0.0", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "number-is-nan": "^1.0.0" }, @@ -16215,15 +16241,17 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/isarray": { "version": "1.0.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/minimatch": { "version": "3.0.4", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -16233,15 +16261,17 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/minimist": { "version": "1.2.5", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/minipass": { "version": "2.9.0", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -16249,9 +16279,10 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/minizlib": { "version": "1.3.3", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "minipass": "^2.9.0" } @@ -16259,9 +16290,10 @@ "node_modules/watchpack/node_modules/fsevents/node_modules/mkdirp": { "version": "0.5.3", "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "minimist": "^1.2.5" }, @@ -16271,15 +16303,17 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/ms": { "version": "2.1.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/needle": { "version": "2.3.3", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "debug": "^3.2.6", "iconv-lite": "^0.4.4", @@ -16294,9 +16328,10 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/node-pre-gyp": { "version": "0.14.0", - "extraneous": true, + "dev": true, "inBundle": true, "license": "BSD-3-Clause", + "optional": true, "dependencies": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", @@ -16315,9 +16350,10 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/nopt": { "version": "4.0.3", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "abbrev": "1", "osenv": "^0.1.4" @@ -16328,24 +16364,27 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/npm-bundled": { "version": "1.1.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "npm-normalize-package-bin": "^1.0.1" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/npm-normalize-package-bin": { "version": "1.0.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/npm-packlist": { "version": "1.4.8", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1", @@ -16354,9 +16393,10 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/npmlog": { "version": "4.1.2", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -16366,54 +16406,60 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/number-is-nan": { "version": "1.0.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/object-assign": { "version": "4.1.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/once": { "version": "1.4.0", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "wrappy": "1" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/os-homedir": { "version": "1.0.2", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/os-tmpdir": { "version": "1.0.2", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/osenv": { "version": "0.1.5", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -16421,24 +16467,27 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/path-is-absolute": { "version": "1.0.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/process-nextick-args": { "version": "2.0.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/rc": { "version": "1.2.8", - "extraneous": true, + "dev": true, "inBundle": true, "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "optional": true, "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -16451,9 +16500,10 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/readable-stream": { "version": "2.3.7", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -16466,9 +16516,10 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/rimraf": { "version": "2.7.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "glob": "^7.1.3" }, @@ -16478,57 +16529,65 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/safe-buffer": { "version": "5.1.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/safer-buffer": { "version": "2.1.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/sax": { "version": "1.2.4", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/semver": { "version": "5.7.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "bin": { "semver": "bin/semver" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/set-blocking": { "version": "2.0.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/signal-exit": { "version": "3.0.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/string_decoder": { "version": "1.1.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "safe-buffer": "~5.1.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/string-width": { "version": "1.0.2", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -16540,9 +16599,10 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/strip-ansi": { "version": "3.0.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "ansi-regex": "^2.0.0" }, @@ -16552,18 +16612,20 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/strip-json-comments": { "version": "2.0.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/tar": { "version": "4.4.13", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", @@ -16579,30 +16641,34 @@ }, "node_modules/watchpack/node_modules/fsevents/node_modules/util-deprecate": { "version": "1.0.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/wide-align": { "version": "1.1.3", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "string-width": "^1.0.2 || 2" } }, "node_modules/watchpack/node_modules/fsevents/node_modules/wrappy": { "version": "1.0.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/watchpack/node_modules/fsevents/node_modules/yallist": { "version": "3.1.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/watchpack/node_modules/is-binary-path": { "version": "1.0.1", @@ -16967,30 +17033,34 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/abbrev": { "version": "1.1.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/ansi-regex": { "version": "2.1.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/aproba": { "version": "1.2.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/are-we-there-yet": { "version": "1.1.5", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -16998,15 +17068,17 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/balanced-match": { "version": "1.0.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/brace-expansion": { "version": "1.1.11", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -17014,66 +17086,75 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/chownr": { "version": "1.1.4", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/code-point-at": { "version": "1.1.0", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/concat-map": { "version": "0.0.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/console-control-strings": { "version": "1.1.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/core-util-is": { "version": "1.0.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/debug": { "version": "3.2.6", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "ms": "^2.1.1" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/deep-extend": { "version": "0.6.0", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=4.0.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/delegates": { "version": "1.0.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/detect-libc": { "version": "1.0.3", - "extraneous": true, + "dev": true, "inBundle": true, "license": "Apache-2.0", + "optional": true, "bin": { "detect-libc": "bin/detect-libc.js" }, @@ -17083,24 +17164,27 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/fs-minipass": { "version": "1.2.7", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "minipass": "^2.6.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/fs.realpath": { "version": "1.0.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/gauge": { "version": "2.7.4", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -17114,9 +17198,10 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/glob": { "version": "7.1.6", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -17134,15 +17219,17 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/has-unicode": { "version": "2.0.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/iconv-lite": { "version": "0.4.24", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -17152,18 +17239,20 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/ignore-walk": { "version": "3.0.3", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "minimatch": "^3.0.4" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/inflight": { "version": "1.0.6", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -17171,24 +17260,27 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/inherits": { "version": "2.0.4", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/ini": { "version": "1.3.5", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "engines": { "node": "*" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/is-fullwidth-code-point": { "version": "1.0.0", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "number-is-nan": "^1.0.0" }, @@ -17198,15 +17290,17 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/isarray": { "version": "1.0.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/minimatch": { "version": "3.0.4", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -17216,15 +17310,17 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/minimist": { "version": "1.2.5", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/minipass": { "version": "2.9.0", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -17232,9 +17328,10 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/minizlib": { "version": "1.3.3", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "minipass": "^2.9.0" } @@ -17242,9 +17339,10 @@ "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/mkdirp": { "version": "0.5.3", "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "minimist": "^1.2.5" }, @@ -17254,15 +17352,17 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/ms": { "version": "2.1.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/needle": { "version": "2.3.3", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "debug": "^3.2.6", "iconv-lite": "^0.4.4", @@ -17277,9 +17377,10 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/node-pre-gyp": { "version": "0.14.0", - "extraneous": true, + "dev": true, "inBundle": true, "license": "BSD-3-Clause", + "optional": true, "dependencies": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", @@ -17298,9 +17399,10 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/nopt": { "version": "4.0.3", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "abbrev": "1", "osenv": "^0.1.4" @@ -17311,24 +17413,27 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/npm-bundled": { "version": "1.1.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "npm-normalize-package-bin": "^1.0.1" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/npm-normalize-package-bin": { "version": "1.0.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/npm-packlist": { "version": "1.4.8", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1", @@ -17337,9 +17442,10 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/npmlog": { "version": "4.1.2", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -17349,54 +17455,60 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/number-is-nan": { "version": "1.0.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/object-assign": { "version": "4.1.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/once": { "version": "1.4.0", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "wrappy": "1" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/os-homedir": { "version": "1.0.2", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/os-tmpdir": { "version": "1.0.2", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/osenv": { "version": "0.1.5", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -17404,24 +17516,27 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/path-is-absolute": { "version": "1.0.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/process-nextick-args": { "version": "2.0.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/rc": { "version": "1.2.8", - "extraneous": true, + "dev": true, "inBundle": true, "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "optional": true, "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -17434,9 +17549,10 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/readable-stream": { "version": "2.3.7", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -17449,9 +17565,10 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/rimraf": { "version": "2.7.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "glob": "^7.1.3" }, @@ -17461,57 +17578,65 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/safe-buffer": { "version": "5.1.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/safer-buffer": { "version": "2.1.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/sax": { "version": "1.2.4", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/semver": { "version": "5.7.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "bin": { "semver": "bin/semver" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/set-blocking": { "version": "2.0.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/signal-exit": { "version": "3.0.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/string_decoder": { "version": "1.1.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "safe-buffer": "~5.1.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/string-width": { "version": "1.0.2", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -17523,9 +17648,10 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/strip-ansi": { "version": "3.0.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "ansi-regex": "^2.0.0" }, @@ -17535,18 +17661,20 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/strip-json-comments": { "version": "2.0.1", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/tar": { "version": "4.4.13", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", @@ -17562,30 +17690,34 @@ }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/util-deprecate": { "version": "1.0.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/wide-align": { "version": "1.1.3", - "extraneous": true, + "dev": true, "inBundle": true, "license": "ISC", + "optional": true, "dependencies": { "string-width": "^1.0.2 || 2" } }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/wrappy": { "version": "1.0.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/webpack-dev-server/node_modules/fsevents/node_modules/yallist": { "version": "3.1.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/webpack-dev-server/node_modules/is-absolute-url": { "version": "3.0.3", @@ -31341,22 +31473,26 @@ "abbrev": { "version": "1.1.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "ansi-regex": { "version": "2.1.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "are-we-there-yet": { "version": "1.1.5", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -31365,12 +31501,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -31379,32 +31517,38 @@ "chownr": { "version": "1.1.4", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "code-point-at": { "version": "1.1.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "debug": { "version": "3.2.6", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "ms": "^2.1.1" } @@ -31412,22 +31556,26 @@ "deep-extend": { "version": "0.6.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "delegates": { "version": "1.0.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "detect-libc": { "version": "1.0.3", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "fs-minipass": { "version": "1.2.7", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "minipass": "^2.6.0" } @@ -31435,12 +31583,14 @@ "fs.realpath": { "version": "1.0.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "gauge": { "version": "2.7.4", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -31455,7 +31605,8 @@ "glob": { "version": "7.1.6", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -31468,12 +31619,14 @@ "has-unicode": { "version": "2.0.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "iconv-lite": { "version": "0.4.24", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -31481,7 +31634,8 @@ "ignore-walk": { "version": "3.0.3", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "minimatch": "^3.0.4" } @@ -31489,7 +31643,8 @@ "inflight": { "version": "1.0.6", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -31498,17 +31653,20 @@ "inherits": { "version": "2.0.4", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -31516,12 +31674,14 @@ "isarray": { "version": "1.0.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "minimatch": { "version": "3.0.4", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -31529,12 +31689,14 @@ "minimist": { "version": "1.2.5", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "minipass": { "version": "2.9.0", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -31543,7 +31705,8 @@ "minizlib": { "version": "1.3.3", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "minipass": "^2.9.0" } @@ -31551,7 +31714,8 @@ "mkdirp": { "version": "0.5.3", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "minimist": "^1.2.5" } @@ -31559,12 +31723,14 @@ "ms": { "version": "2.1.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "needle": { "version": "2.3.3", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "debug": "^3.2.6", "iconv-lite": "^0.4.4", @@ -31574,7 +31740,8 @@ "node-pre-gyp": { "version": "0.14.0", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", @@ -31591,7 +31758,8 @@ "nopt": { "version": "4.0.3", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "abbrev": "1", "osenv": "^0.1.4" @@ -31600,7 +31768,8 @@ "npm-bundled": { "version": "1.1.1", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "npm-normalize-package-bin": "^1.0.1" } @@ -31608,12 +31777,14 @@ "npm-normalize-package-bin": { "version": "1.0.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "npm-packlist": { "version": "1.4.8", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1", @@ -31623,7 +31794,8 @@ "npmlog": { "version": "4.1.2", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -31634,17 +31806,20 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "once": { "version": "1.4.0", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -31652,17 +31827,20 @@ "os-homedir": { "version": "1.0.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "os-tmpdir": { "version": "1.0.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "osenv": { "version": "0.1.5", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -31671,17 +31849,20 @@ "path-is-absolute": { "version": "1.0.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "process-nextick-args": { "version": "2.0.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "rc": { "version": "1.2.8", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -31692,7 +31873,8 @@ "readable-stream": { "version": "2.3.7", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -31706,7 +31888,8 @@ "rimraf": { "version": "2.7.1", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "glob": "^7.1.3" } @@ -31714,37 +31897,44 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "sax": { "version": "1.2.4", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "semver": { "version": "5.7.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "set-blocking": { "version": "2.0.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "signal-exit": { "version": "3.0.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "string_decoder": { "version": "1.1.1", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -31752,7 +31942,8 @@ "string-width": { "version": "1.0.2", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -31762,7 +31953,8 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -31770,12 +31962,14 @@ "strip-json-comments": { "version": "2.0.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "tar": { "version": "4.4.13", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", @@ -31789,12 +31983,14 @@ "util-deprecate": { "version": "1.0.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "wide-align": { "version": "1.1.3", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "string-width": "^1.0.2 || 2" } @@ -31802,12 +31998,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "yallist": { "version": "3.1.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true } } }, @@ -32222,22 +32420,26 @@ "abbrev": { "version": "1.1.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "ansi-regex": { "version": "2.1.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "are-we-there-yet": { "version": "1.1.5", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^2.0.6" @@ -32246,12 +32448,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -32260,32 +32464,38 @@ "chownr": { "version": "1.1.4", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "code-point-at": { "version": "1.1.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "debug": { "version": "3.2.6", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "ms": "^2.1.1" } @@ -32293,22 +32503,26 @@ "deep-extend": { "version": "0.6.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "delegates": { "version": "1.0.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "detect-libc": { "version": "1.0.3", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "fs-minipass": { "version": "1.2.7", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "minipass": "^2.6.0" } @@ -32316,12 +32530,14 @@ "fs.realpath": { "version": "1.0.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "gauge": { "version": "2.7.4", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -32336,7 +32552,8 @@ "glob": { "version": "7.1.6", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -32349,12 +32566,14 @@ "has-unicode": { "version": "2.0.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "iconv-lite": { "version": "0.4.24", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -32362,7 +32581,8 @@ "ignore-walk": { "version": "3.0.3", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "minimatch": "^3.0.4" } @@ -32370,7 +32590,8 @@ "inflight": { "version": "1.0.6", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -32379,17 +32600,20 @@ "inherits": { "version": "2.0.4", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -32397,12 +32621,14 @@ "isarray": { "version": "1.0.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "minimatch": { "version": "3.0.4", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -32410,12 +32636,14 @@ "minimist": { "version": "1.2.5", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "minipass": { "version": "2.9.0", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -32424,7 +32652,8 @@ "minizlib": { "version": "1.3.3", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "minipass": "^2.9.0" } @@ -32432,7 +32661,8 @@ "mkdirp": { "version": "0.5.3", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "minimist": "^1.2.5" } @@ -32440,12 +32670,14 @@ "ms": { "version": "2.1.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "needle": { "version": "2.3.3", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "debug": "^3.2.6", "iconv-lite": "^0.4.4", @@ -32455,7 +32687,8 @@ "node-pre-gyp": { "version": "0.14.0", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", @@ -32472,7 +32705,8 @@ "nopt": { "version": "4.0.3", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "abbrev": "1", "osenv": "^0.1.4" @@ -32481,7 +32715,8 @@ "npm-bundled": { "version": "1.1.1", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "npm-normalize-package-bin": "^1.0.1" } @@ -32489,12 +32724,14 @@ "npm-normalize-package-bin": { "version": "1.0.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "npm-packlist": { "version": "1.4.8", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "ignore-walk": "^3.0.1", "npm-bundled": "^1.0.1", @@ -32504,7 +32741,8 @@ "npmlog": { "version": "4.1.2", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -32515,17 +32753,20 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "once": { "version": "1.4.0", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -32533,17 +32774,20 @@ "os-homedir": { "version": "1.0.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "os-tmpdir": { "version": "1.0.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "osenv": { "version": "0.1.5", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -32552,17 +32796,20 @@ "path-is-absolute": { "version": "1.0.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "process-nextick-args": { "version": "2.0.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "rc": { "version": "1.2.8", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -32573,7 +32820,8 @@ "readable-stream": { "version": "2.3.7", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -32587,7 +32835,8 @@ "rimraf": { "version": "2.7.1", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "glob": "^7.1.3" } @@ -32595,37 +32844,44 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "sax": { "version": "1.2.4", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "semver": { "version": "5.7.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "set-blocking": { "version": "2.0.0", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "signal-exit": { "version": "3.0.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "string_decoder": { "version": "1.1.1", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "safe-buffer": "~5.1.0" } @@ -32633,7 +32889,8 @@ "string-width": { "version": "1.0.2", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -32643,7 +32900,8 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -32651,12 +32909,14 @@ "strip-json-comments": { "version": "2.0.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "tar": { "version": "4.4.13", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", @@ -32670,12 +32930,14 @@ "util-deprecate": { "version": "1.0.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "wide-align": { "version": "1.1.3", "bundled": true, - "extraneous": true, + "dev": true, + "optional": true, "requires": { "string-width": "^1.0.2 || 2" } @@ -32683,12 +32945,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "extraneous": true + "dev": true, + "optional": true }, "yallist": { "version": "3.1.1", "bundled": true, - "extraneous": true + "dev": true, + "optional": true } } }, From 772063a84389bef1cb699b9cdf2340da83161596 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Tue, 16 Nov 2021 19:07:37 -0800 Subject: [PATCH 042/114] find the temp history for the last week (by default). Smooth out data using aggregate window for hourly numbers. Better temp casting during influx data inflating. --- webapp/backend/pkg/database/scrutiny_repository.go | 4 ++-- .../backend/pkg/models/measurements/smart_temperature.go | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index 530348b..6c31c83 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -522,9 +522,9 @@ func (sr *scrutinyRepository) GetSmartTemperatureHistory(ctx context.Context) (m queryStr := fmt.Sprintf(` import "influxdata/influxdb/schema" from(bucket: "%s") - |> range(start: -3y, stop: now()) + |> range(start: -1w, stop: now()) |> filter(fn: (r) => r["_measurement"] == "temp" ) - |> filter(fn: (r) => r["_field"] == "temp") + |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) |> schema.fieldsAsCols() |> group(columns: ["device_wwn"]) |> yield(name: "last") diff --git a/webapp/backend/pkg/models/measurements/smart_temperature.go b/webapp/backend/pkg/models/measurements/smart_temperature.go index 06f4d74..e29e79e 100644 --- a/webapp/backend/pkg/models/measurements/smart_temperature.go +++ b/webapp/backend/pkg/models/measurements/smart_temperature.go @@ -24,6 +24,11 @@ func (st *SmartTemperature) Inflate(key string, val interface{}) { } if key == "temp" { - st.Temp = val.(int64) + switch t := val.(type) { + case int64: + st.Temp = t + case float64: + st.Temp = int64(t) + } } } From 03bfdd3890ef99ef8e650fe72205e2122d713837 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Tue, 16 Nov 2021 20:39:09 -0800 Subject: [PATCH 043/114] changing the duration dropdown for temp history data. adding an /api/summary/temp endpoint --- webapp/backend/pkg/database/interface.go | 1 + .../pkg/database/scrutiny_repository.go | 54 +++++++++++++++++-- .../get_devices_summary_temp_history.go | 32 +++++++++++ webapp/backend/pkg/web/server.go | 7 +-- .../dashboard/dashboard.component.html | 7 ++- 5 files changed, 89 insertions(+), 12 deletions(-) create mode 100644 webapp/backend/pkg/web/handler/get_devices_summary_temp_history.go diff --git a/webapp/backend/pkg/database/interface.go b/webapp/backend/pkg/database/interface.go index bc52475..9e50596 100644 --- a/webapp/backend/pkg/database/interface.go +++ b/webapp/backend/pkg/database/interface.go @@ -26,4 +26,5 @@ type DeviceRepo interface { SaveSmartTemperature(ctx context.Context, wwn string, deviceProtocol string, collectorSmartData collector.SmartInfo) error GetSummary(ctx context.Context) (map[string]*models.DeviceSummary, error) + GetSmartTemperatureHistory(ctx context.Context, durationKey string) (map[string][]measurements.SmartTemperature, error) } diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index 6c31c83..3e2c61b 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -289,7 +289,7 @@ func (sr *scrutinyRepository) DownsampleScript(aggregationType string) string { smart_data = from(bucket: sourceBucket) |> range(start: rangeStart, stop: rangeEnd) |> filter(fn: (r) => r["_measurement"] == "smart" ) - |> filter(fn: (r) => r["_field"] !~ /(raw_string|_measurement|device_protocol|device_wwn|attribute_id|when_failed)/) + |> filter(fn: (r) => r["_field"] !~ /(raw_string|_measurement|device_protocol|status_reason|device_wwn|attribute_id|when_failed)/) |> last() |> yield(name: "last") @@ -514,7 +514,8 @@ func (sr *scrutinyRepository) SaveSmartTemperature(ctx context.Context, wwn stri return nil } -func (sr *scrutinyRepository) GetSmartTemperatureHistory(ctx context.Context) (map[string][]measurements.SmartTemperature, error) { +func (sr *scrutinyRepository) GetSmartTemperatureHistory(ctx context.Context, durationKey string) (map[string][]measurements.SmartTemperature, error) { + //we can get temp history for "week", "month", "year", "forever" deviceTempHistory := map[string][]measurements.SmartTemperature{} @@ -522,14 +523,15 @@ func (sr *scrutinyRepository) GetSmartTemperatureHistory(ctx context.Context) (m queryStr := fmt.Sprintf(` import "influxdata/influxdb/schema" from(bucket: "%s") - |> range(start: -1w, stop: now()) + |> range(start: %s, stop: now()) |> filter(fn: (r) => r["_measurement"] == "temp" ) |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) |> schema.fieldsAsCols() |> group(columns: ["device_wwn"]) |> yield(name: "last") `, - sr.appConfig.GetString("web.influxdb.bucket"), + sr.lookupBucketName(durationKey), + sr.lookupDuration(durationKey), ) result, err := sr.influxQueryApi.Query(ctx, queryStr) @@ -590,6 +592,7 @@ func (sr *scrutinyRepository) GetSummary(ctx context.Context) (map[string]*model |> range(start: -1y, stop: now()) |> filter(fn: (r) => r["_measurement"] == "smart" ) |> filter(fn: (r) => r["_field"] == "temp" or r["_field"] == "power_on_hours" or r["_field"] == "date") + |> last() |> schema.fieldsAsCols() |> group(columns: ["device_wwn"]) |> yield(name: "last") @@ -630,7 +633,7 @@ func (sr *scrutinyRepository) GetSummary(ctx context.Context) (map[string]*model return nil, err } - deviceTempHistory, err := sr.GetSmartTemperatureHistory(ctx) + deviceTempHistory, err := sr.GetSmartTemperatureHistory(ctx, "week") if err != nil { sr.logger.Printf("========================>>>>>>>>======================") sr.logger.Printf("========================>>>>>>>>======================") @@ -645,3 +648,44 @@ func (sr *scrutinyRepository) GetSummary(ctx context.Context) (map[string]*model return summaries, nil } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Helper Methods +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +func (sr *scrutinyRepository) lookupBucketName(durationKey string) string { + switch durationKey { + case "week": + //data stored in the last week + return sr.appConfig.GetString("web.influxdb.bucket") + case "month": + // data stored in the last month (after the first week) + return fmt.Sprintf("%s_weekly", sr.appConfig.GetString("web.influxdb.bucket")) + case "year": + // data stored in the last year (after the first month) + return fmt.Sprintf("%s_monthly", sr.appConfig.GetString("web.influxdb.bucket")) + case "forever": + //data stored before the last year + return fmt.Sprintf("%s_yearly", sr.appConfig.GetString("web.influxdb.bucket")) + } + return sr.appConfig.GetString("web.influxdb.bucket") +} + +func (sr *scrutinyRepository) lookupDuration(durationKey string) string { + + switch durationKey { + case "week": + //data stored in the last week + return "-1w" + case "month": + // data stored in the last month (after the first week) + return "-1mo" + case "year": + // data stored in the last year (after the first month) + return "-1y" + case "forever": + //data stored before the last year + return "-10y" + } + return "-1w" +} diff --git a/webapp/backend/pkg/web/handler/get_devices_summary_temp_history.go b/webapp/backend/pkg/web/handler/get_devices_summary_temp_history.go new file mode 100644 index 0000000..631b9ec --- /dev/null +++ b/webapp/backend/pkg/web/handler/get_devices_summary_temp_history.go @@ -0,0 +1,32 @@ +package handler + +import ( + "github.com/analogj/scrutiny/webapp/backend/pkg/database" + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" + "net/http" +) + +func GetDevicesSummaryTempHistory(c *gin.Context) { + logger := c.MustGet("LOGGER").(logrus.FieldLogger) + deviceRepo := c.MustGet("DEVICE_REPOSITORY").(database.DeviceRepo) + + durationKey, exists := c.GetQuery("duration_key") + if !exists { + durationKey = "week" + } + + tempHistory, err := deviceRepo.GetSmartTemperatureHistory(c, durationKey) + if err != nil { + logger.Errorln("An error occurred while retrieving summary/temp history", err) + c.JSON(http.StatusInternalServerError, gin.H{"success": false}) + return + } + + c.JSON(http.StatusOK, gin.H{ + "success": true, + "data": map[string]interface{}{ + "temp_history": tempHistory, + }, + }) +} diff --git a/webapp/backend/pkg/web/server.go b/webapp/backend/pkg/web/server.go index c685916..078e216 100644 --- a/webapp/backend/pkg/web/server.go +++ b/webapp/backend/pkg/web/server.go @@ -36,9 +36,10 @@ func (ae *AppEngine) Setup(logger logrus.FieldLogger) *gin.Engine { }) api.POST("/health/notify", handler.SendTestNotification) //check if notifications are configured correctly - api.POST("/devices/register", handler.RegisterDevices) //used by Collector to register new devices and retrieve filtered list - api.GET("/summary", handler.GetDevicesSummary) //used by Dashboard - api.POST("/device/:wwn/smart", handler.UploadDeviceMetrics) //used by Collector to upload data + api.POST("/devices/register", handler.RegisterDevices) //used by Collector to register new devices and retrieve filtered list + api.GET("/summary", handler.GetDevicesSummary) //used by Dashboard + api.GET("/summary/temp", handler.GetDevicesSummaryTempHistory) //used by Dashboard (Temperature history dropdown) + api.POST("/device/:wwn/smart", handler.UploadDeviceMetrics) //used by Collector to upload data api.POST("/device/:wwn/selftest", handler.UploadDeviceSelfTests) api.GET("/device/:wwn/details", handler.GetDeviceDetails) //used by Details } diff --git a/webapp/frontend/src/app/modules/dashboard/dashboard.component.html b/webapp/frontend/src/app/modules/dashboard/dashboard.component.html index 4fd1574..a63f8d2 100644 --- a/webapp/frontend/src/app/modules/dashboard/dashboard.component.html +++ b/webapp/frontend/src/app/modules/dashboard/dashboard.component.html @@ -127,13 +127,12 @@ matTooltip="not yet implemented" mat-button [matMenuTriggerFor]="accountBalanceMenu"> - 12 months + 1 week - - - + +
From bff83de3a059dcc875eeee231481143d933e62ab Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Wed, 17 Nov 2021 18:35:50 -0800 Subject: [PATCH 044/114] query temp data across multiple buckets --- .../pkg/database/scrutiny_repository.go | 102 ++++++++++++++---- 1 file changed, 83 insertions(+), 19 deletions(-) diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index 3e2c61b..0753a48 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -15,6 +15,7 @@ import ( "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/clause" + "strings" "time" ) @@ -520,19 +521,7 @@ func (sr *scrutinyRepository) GetSmartTemperatureHistory(ctx context.Context, du deviceTempHistory := map[string][]measurements.SmartTemperature{} //TODO: change the query range to a variable. - queryStr := fmt.Sprintf(` - import "influxdata/influxdb/schema" - from(bucket: "%s") - |> range(start: %s, stop: now()) - |> filter(fn: (r) => r["_measurement"] == "temp" ) - |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) - |> schema.fieldsAsCols() - |> group(columns: ["device_wwn"]) - |> yield(name: "last") - `, - sr.lookupBucketName(durationKey), - sr.lookupDuration(durationKey), - ) + queryStr := sr.aggregateTempQuery(durationKey) result, err := sr.influxQueryApi.Query(ctx, queryStr) if err == nil { @@ -671,21 +660,96 @@ func (sr *scrutinyRepository) lookupBucketName(durationKey string) string { return sr.appConfig.GetString("web.influxdb.bucket") } -func (sr *scrutinyRepository) lookupDuration(durationKey string) string { +func (sr *scrutinyRepository) lookupDuration(durationKey string) []string { switch durationKey { case "week": //data stored in the last week - return "-1w" + return []string{"-1w", "now()"} case "month": // data stored in the last month (after the first week) - return "-1mo" + return []string{"-1mo", "-1w"} case "year": // data stored in the last year (after the first month) - return "-1y" + return []string{"-1y", "-1mo"} case "forever": //data stored before the last year - return "-10y" + return []string{"-10y", "-1y"} } - return "-1w" + return []string{"-1w", "now()"} +} + +func (sr *scrutinyRepository) lookupNestedDurationKeys(durationKey string) []string { + switch durationKey { + case "week": + //all data is stored in a single bucket + return []string{"week"} + case "month": + //data is stored in the week bucket and the month bucket + return []string{"week", "month"} + case "year": + // data stored in the last year (after the first month) + return []string{"week", "month", "year"} + case "forever": + //data stored before the last year + return []string{"week", "month", "year"} + } + return []string{"week"} +} + +func (sr *scrutinyRepository) aggregateTempQuery(durationKey string) string { + + //TODO: change the query range to a variable. + //queryStr := fmt.Sprintf(` + //import "influxdata/influxdb/schema" + //from(bucket: "%s") + //|> range(start: %s, stop: now()) + //|> filter(fn: (r) => r["_measurement"] == "temp" ) + //|> aggregateWindow(every: 1h, fn: mean, createEmpty: false) + //|> schema.fieldsAsCols() + //|> group(columns: ["device_wwn"]) + //|> yield(name: "last") + // `, + // sr.lookupBucketName(durationKey), + // sr.lookupDuration(durationKey), + //) + + partialQueryStr := []string{`import "influxdata/influxdb/schema"`} + + nestedDurationKeys := sr.lookupNestedDurationKeys(durationKey) + + subQueryNames := []string{} + for _, nestedDurationKey := range nestedDurationKeys { + bucketName := sr.lookupBucketName(nestedDurationKey) + durationRange := sr.lookupDuration(nestedDurationKey) + + subQueryNames = append(subQueryNames, fmt.Sprintf(`%sData`, nestedDurationKey)) + partialQueryStr = append(partialQueryStr, []string{ + fmt.Sprintf(`%sData = from(bucket: "%s")`, nestedDurationKey, bucketName), + fmt.Sprintf(`|> range(start: %s, stop: %s)`, durationRange[0], durationRange[1]), + `|> filter(fn: (r) => r["_measurement"] == "temp" )`, + `|> aggregateWindow(every: 1h, fn: mean, createEmpty: false)`, + `|> group(columns: ["device_wwn"])`, + `|> toInt()`, + "", + }...) + } + + if len(subQueryNames) == 1 { + //there's only one bucket being queried, no need to union, just aggregate the dataset and return + partialQueryStr = append(partialQueryStr, []string{ + subQueryNames[0], + "|> schema.fieldsAsCols()", + "|> yield()", + }...) + } else { + partialQueryStr = append(partialQueryStr, []string{ + fmt.Sprintf("union(tables: [%s])", strings.Join(subQueryNames, ", ")), + `|> group(columns: ["device_wwn"])`, + `|> sort(columns: ["_time"], desc: false)`, + "|> schema.fieldsAsCols()", + }...) + } + + return strings.Join(partialQueryStr, "\n") } From 47e8595c9d5666d259ed0efa343c2e83af89221c Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Wed, 17 Nov 2021 20:50:18 -0800 Subject: [PATCH 045/114] using constant vars for duration key magic strings. Fixing Errorf calls to correctly have template data. --- .../pkg/database/scrutiny_repository.go | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index 0753a48..e5429f8 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -28,6 +28,11 @@ const ( // 60seconds * 60minutes * 24hours * 7 days * (52 + 52 + 4)weeks RETENTION_PERIOD_25_MONTHS_IN_SECONDS = 65_318_400 + + DURATION_KEY_WEEK = "week" + DURATION_KEY_MONTH = "month" + DURATION_KEY_YEAR = "year" + DURATION_KEY_FOREVER = "forever" ) //// GormLogger is a custom logger for Gorm, making it use logrus. @@ -63,7 +68,7 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field //Logger: logger }) if err != nil { - return nil, fmt.Errorf("Failed to connect to database!") + return nil, fmt.Errorf("Failed to connect to database! - %v", err) } //database.SetLogger() @@ -338,7 +343,7 @@ func (sr *scrutinyRepository) GetDevices(ctx context.Context) ([]models.Device, //Get a list of all the active devices. devices := []models.Device{} if err := sr.gormClient.WithContext(ctx).Find(&devices).Error; err != nil { - return nil, fmt.Errorf("Could not get device summary from DB", err) + return nil, fmt.Errorf("Could not get device summary from DB: %v", err) } return devices, nil } @@ -347,7 +352,7 @@ func (sr *scrutinyRepository) GetDevices(ctx context.Context) ([]models.Device, func (sr *scrutinyRepository) UpdateDevice(ctx context.Context, wwn string, collectorSmartData collector.SmartInfo) (models.Device, error) { var device models.Device if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil { - return device, fmt.Errorf("Could not get device from DB", err) + return device, fmt.Errorf("Could not get device from DB: %v", err) } //TODO catch GormClient err @@ -362,7 +367,7 @@ func (sr *scrutinyRepository) UpdateDevice(ctx context.Context, wwn string, coll func (sr *scrutinyRepository) UpdateDeviceStatus(ctx context.Context, wwn string, status pkg.DeviceStatus) (models.Device, error) { var device models.Device if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil { - return device, fmt.Errorf("Could not get device from DB", err) + return device, fmt.Errorf("Could not get device from DB: %v", err) } device.DeviceStatus = pkg.Set(device.DeviceStatus, status) @@ -516,7 +521,7 @@ func (sr *scrutinyRepository) SaveSmartTemperature(ctx context.Context, wwn stri } func (sr *scrutinyRepository) GetSmartTemperatureHistory(ctx context.Context, durationKey string) (map[string][]measurements.SmartTemperature, error) { - //we can get temp history for "week", "month", "year", "forever" + //we can get temp history for "week", "month", DURATION_KEY_YEAR, "forever" deviceTempHistory := map[string][]measurements.SmartTemperature{} @@ -622,7 +627,7 @@ func (sr *scrutinyRepository) GetSummary(ctx context.Context) (map[string]*model return nil, err } - deviceTempHistory, err := sr.GetSmartTemperatureHistory(ctx, "week") + deviceTempHistory, err := sr.GetSmartTemperatureHistory(ctx, DURATION_KEY_WEEK) if err != nil { sr.logger.Printf("========================>>>>>>>>======================") sr.logger.Printf("========================>>>>>>>>======================") @@ -644,16 +649,16 @@ func (sr *scrutinyRepository) GetSummary(ctx context.Context) (map[string]*model func (sr *scrutinyRepository) lookupBucketName(durationKey string) string { switch durationKey { - case "week": + case DURATION_KEY_WEEK: //data stored in the last week return sr.appConfig.GetString("web.influxdb.bucket") - case "month": + case DURATION_KEY_MONTH: // data stored in the last month (after the first week) return fmt.Sprintf("%s_weekly", sr.appConfig.GetString("web.influxdb.bucket")) - case "year": + case DURATION_KEY_YEAR: // data stored in the last year (after the first month) return fmt.Sprintf("%s_monthly", sr.appConfig.GetString("web.influxdb.bucket")) - case "forever": + case DURATION_KEY_FOREVER: //data stored before the last year return fmt.Sprintf("%s_yearly", sr.appConfig.GetString("web.influxdb.bucket")) } @@ -663,16 +668,16 @@ func (sr *scrutinyRepository) lookupBucketName(durationKey string) string { func (sr *scrutinyRepository) lookupDuration(durationKey string) []string { switch durationKey { - case "week": + case DURATION_KEY_WEEK: //data stored in the last week return []string{"-1w", "now()"} - case "month": + case DURATION_KEY_MONTH: // data stored in the last month (after the first week) return []string{"-1mo", "-1w"} - case "year": + case DURATION_KEY_YEAR: // data stored in the last year (after the first month) return []string{"-1y", "-1mo"} - case "forever": + case DURATION_KEY_FOREVER: //data stored before the last year return []string{"-10y", "-1y"} } @@ -681,20 +686,20 @@ func (sr *scrutinyRepository) lookupDuration(durationKey string) []string { func (sr *scrutinyRepository) lookupNestedDurationKeys(durationKey string) []string { switch durationKey { - case "week": + case DURATION_KEY_WEEK: //all data is stored in a single bucket - return []string{"week"} - case "month": + return []string{DURATION_KEY_WEEK} + case DURATION_KEY_MONTH: //data is stored in the week bucket and the month bucket - return []string{"week", "month"} - case "year": + return []string{DURATION_KEY_WEEK, DURATION_KEY_MONTH} + case DURATION_KEY_YEAR: // data stored in the last year (after the first month) - return []string{"week", "month", "year"} - case "forever": + return []string{DURATION_KEY_WEEK, DURATION_KEY_MONTH, DURATION_KEY_YEAR} + case DURATION_KEY_FOREVER: //data stored before the last year - return []string{"week", "month", "year"} + return []string{DURATION_KEY_WEEK, DURATION_KEY_MONTH, DURATION_KEY_YEAR} } - return []string{"week"} + return []string{DURATION_KEY_WEEK} } func (sr *scrutinyRepository) aggregateTempQuery(durationKey string) string { From 0872da57d7821aac0a855de526978859ed6c7449 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Wed, 17 Nov 2021 21:08:56 -0800 Subject: [PATCH 046/114] fixes for tests. --- webapp/backend/pkg/models/measurements/smart.go | 3 ++- webapp/backend/pkg/web/server_test.go | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/webapp/backend/pkg/models/measurements/smart.go b/webapp/backend/pkg/models/measurements/smart.go index d0c3a39..37810f4 100644 --- a/webapp/backend/pkg/models/measurements/smart.go +++ b/webapp/backend/pkg/models/measurements/smart.go @@ -6,6 +6,7 @@ import ( "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" "github.com/analogj/scrutiny/webapp/backend/pkg/thresholds" "log" + "strconv" "strings" "time" ) @@ -155,7 +156,7 @@ func (sm *Smart) ProcessAtaSmartInfo(info collector.SmartInfo) { } } attrModel.PopulateAttributeStatus() - sm.Attributes[string(collectorAttr.ID)] = &attrModel + sm.Attributes[strconv.Itoa(collectorAttr.ID)] = &attrModel if attrModel.Status == pkg.SmartAttributeStatusFailed { sm.Status = pkg.DeviceStatusFailedScrutiny } diff --git a/webapp/backend/pkg/web/server_test.go b/webapp/backend/pkg/web/server_test.go index b70a31c..0a247e7 100644 --- a/webapp/backend/pkg/web/server_test.go +++ b/webapp/backend/pkg/web/server_test.go @@ -76,6 +76,7 @@ func TestHealthRoute(t *testing.T) { fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() + fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() ae := web.AppEngine{ Config: fakeConfig, @@ -108,6 +109,7 @@ func TestRegisterDevicesRoute(t *testing.T) { fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() + fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() ae := web.AppEngine{ Config: fakeConfig, @@ -140,6 +142,7 @@ func TestUploadDeviceMetricsRoute(t *testing.T) { fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() + fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() ae := web.AppEngine{ Config: fakeConfig, @@ -181,6 +184,7 @@ func TestPopulateMultiple(t *testing.T) { fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() + fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() ae := web.AppEngine{ Config: fakeConfig, @@ -269,6 +273,7 @@ func TestSendTestNotificationRoute_WebhookFailure(t *testing.T) { fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() + fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"https://unroutable.domain.example.asdfghj"}) ae := web.AppEngine{ Config: fakeConfig, @@ -299,6 +304,7 @@ func TestSendTestNotificationRoute_ScriptFailure(t *testing.T) { fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() + fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"script:///missing/path/on/disk"}) ae := web.AppEngine{ Config: fakeConfig, @@ -329,6 +335,7 @@ func TestSendTestNotificationRoute_ScriptSuccess(t *testing.T) { fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() + fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"script:///usr/bin/env"}) ae := web.AppEngine{ @@ -360,6 +367,8 @@ func TestSendTestNotificationRoute_ShoutrrrFailure(t *testing.T) { fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() + fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() + fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"discord://invalidtoken@channel"}) ae := web.AppEngine{ Config: fakeConfig, @@ -390,6 +399,7 @@ func TestGetDevicesSummaryRoute_Nvme(t *testing.T) { fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() + fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{}) ae := web.AppEngine{ From 903d5713fc69fa8c944e8611702af9473508a05c Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 21 Nov 2021 14:39:39 -0800 Subject: [PATCH 047/114] fixes for tests. --- docs/DOWNSAMPLING.md | 42 +++++++++++++++++++ .../pkg/database/scrutiny_repository.go | 41 ++++++++++-------- 2 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 docs/DOWNSAMPLING.md diff --git a/docs/DOWNSAMPLING.md b/docs/DOWNSAMPLING.md new file mode 100644 index 0000000..25a202a --- /dev/null +++ b/docs/DOWNSAMPLING.md @@ -0,0 +1,42 @@ +# Downsampling + +Scrutiny collects alot of data, that can cause the database to grow unbounded. + +- Smart data +- Smart test data +- Temperature data +- Disk metrics (capacity/usage) +- etc + +This data must be accurate in the short term, and is useful for doing trend analysis in the long term. +However, for trend analysis we only need aggregate data, individual data points are not as useful. + +Scrutiny will automatically downsample data on a schedule to ensure that the database size stays reasonable, while still +ensuring historical data is present for comparisons. + + +| Bucket Name | Retention Period | Downsampling Range | Downsampling Aggregation Window | Downsampling Cron | Comments | +| --- | --- | --- | --- | --- | --- | +| `metrics` | 15 days | `-2w -1w` | `1w` | weekly on Sunday at 1:00am | +| `metrics_weekly` | 9 weeks | `-2mo -1mo` | `1mo` | monthly on first day of the month at 1:30am +| `metrics_monthly` | 25 months | `-2y -1y` | `1y` | yearly on the first day of the year at 2:00am +| `metrics_yearly` | forever | - | - | - | | + + +After 5 months, here's how may data points should exist in each bucket for one disk + +| Bucket Name | Datapoints | Comments | +| --- | --- | --- | +| `metrics` | 15 | 7 daily datapoints , up to 7 pending data, 1 buffer data point | +| `metrics_weekly` | 9 | 4 aggregated weekly data points, 4 pending datapoints, 1 buffer data point | +| `metrics_monthly` | 3 | 3 aggregated monthly data points | +| `metrics_yearly` | 0 | | + +After 5 years, here's how may data points should exist in each bucket for one disk + +| Bucket Name | Datapoints | Comments | +| --- | --- | --- | +| `metrics` | - | - | +| `metrics_weekly` | - | +| `metrics_monthly` | - | +| `metrics_yearly` | - | diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index e5429f8..1a99257 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -295,8 +295,7 @@ func (sr *scrutinyRepository) DownsampleScript(aggregationType string) string { smart_data = from(bucket: sourceBucket) |> range(start: rangeStart, stop: rangeEnd) |> filter(fn: (r) => r["_measurement"] == "smart" ) - |> filter(fn: (r) => r["_field"] !~ /(raw_string|_measurement|device_protocol|status_reason|device_wwn|attribute_id|when_failed)/) - |> last() + |> filter(fn: (r) => r["_field"] !~ /(_measurement|device_protocol|device_wwn|attribute_id|raw_string|status_reason|when_failed)/) |> yield(name: "last") smart_data @@ -306,7 +305,7 @@ func (sr *scrutinyRepository) DownsampleScript(aggregationType string) string { temp_data = from(bucket: sourceBucket) |> range(start: rangeStart, stop: rangeEnd) |> filter(fn: (r) => r["_measurement"] == "temp") - |> last() + |> toInt() |> yield(name: "mean") temp_data @@ -704,20 +703,28 @@ func (sr *scrutinyRepository) lookupNestedDurationKeys(durationKey string) []str func (sr *scrutinyRepository) aggregateTempQuery(durationKey string) string { - //TODO: change the query range to a variable. - //queryStr := fmt.Sprintf(` - //import "influxdata/influxdb/schema" - //from(bucket: "%s") - //|> range(start: %s, stop: now()) - //|> filter(fn: (r) => r["_measurement"] == "temp" ) - //|> aggregateWindow(every: 1h, fn: mean, createEmpty: false) - //|> schema.fieldsAsCols() - //|> group(columns: ["device_wwn"]) - //|> yield(name: "last") - // `, - // sr.lookupBucketName(durationKey), - // sr.lookupDuration(durationKey), - //) + /* + import "influxdata/influxdb/schema" + weekData = from(bucket: "metrics") + |> range(start: -1w, stop: now()) + |> filter(fn: (r) => r["_measurement"] == "temp" ) + |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) + |> group(columns: ["device_wwn"]) + |> toInt() + + monthData = from(bucket: "metrics_weekly") + |> range(start: -1mo, stop: now()) + |> filter(fn: (r) => r["_measurement"] == "temp" ) + |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) + |> group(columns: ["device_wwn"]) + |> toInt() + + union(tables: [weekData, monthData]) + |> group(columns: ["device_wwn"]) + |> sort(columns: ["_time"], desc: false) + |> schema.fieldsAsCols() + + */ partialQueryStr := []string{`import "influxdata/influxdb/schema"`} From a8952eff0ca7e1cf1a7d55f2f1a25a0b99243694 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Wed, 5 Jan 2022 21:03:37 +0800 Subject: [PATCH 048/114] Improve README.md a little bit Set indentation of docker commands, and set the language of code block to enable syntax highlight in README.md --- README.md | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index ec090c5..9a7a422 100644 --- a/README.md +++ b/README.md @@ -72,12 +72,12 @@ If you're using Docker, getting started is as simple as running the following co ```bash docker run -it --rm -p 8080:8080 \ --v /run/udev:/run/udev:ro \ ---cap-add SYS_RAWIO \ ---device=/dev/sda \ ---device=/dev/sdb \ ---name scrutiny \ -analogj/scrutiny + -v /run/udev:/run/udev:ro \ + --cap-add SYS_RAWIO \ + --device=/dev/sda \ + --device=/dev/sdb \ + --name scrutiny \ + analogj/scrutiny ``` - `/run/udev` is necessary to provide the Scrutiny collector with access to your device metadata @@ -95,17 +95,17 @@ In addition to the Omnibus image (available under the `latest` tag) there are 2 ```bash docker run -it --rm -p 8080:8080 \ ---name scrutiny-web \ -analogj/scrutiny:web + --name scrutiny-web \ + analogj/scrutiny:web docker run -it --rm \ --v /run/udev:/run/udev:ro \ ---cap-add SYS_RAWIO \ ---device=/dev/sda \ ---device=/dev/sdb \ --e SCRUTINY_API_ENDPOINT=http://SCRUTINY_WEB_IPADDRESS:8080 \ ---name scrutiny-collector \ -analogj/scrutiny:collector + -v /run/udev:/run/udev:ro \ + --cap-add SYS_RAWIO \ + --device=/dev/sda \ + --device=/dev/sdb \ + -e SCRUTINY_API_ENDPOINT=http://SCRUTINY_WEB_IPADDRESS:8080 \ + --name scrutiny-collector \ + analogj/scrutiny:collector ``` ## Manual Installation (without-Docker) @@ -126,7 +126,7 @@ drive that Scrutiny detected. The collector is configured to run once a day, but For users of the docker Hub/Spoke deployment or manual install: initially the dashboard will be empty. After the first collector run, you'll be greeted with a list of all your hard drives and their current smart status. -``` +```bash docker exec scrutiny /scrutiny/bin/scrutiny-collector-metrics run ``` @@ -165,7 +165,7 @@ Check the `notify.urls` section of [example.scrutiny.yml](example.scrutiny.yaml) You can test that your notifications are configured correctly by posting an empty payload to the notifications health check API. -``` +```bash curl -X POST http://localhost:8080/api/health/notify ``` @@ -176,14 +176,14 @@ Scrutiny provides various methods to change the log level to debug and generate You can use environmental variables to enable debug logging and/or log files for the web server: -``` +```bash DEBUG=true SCRUTINY_LOG_FILE=/tmp/web.log ``` You can configure the log level and log file in the config file: -``` +```yml log: file: '/tmp/web.log' level: DEBUG @@ -191,7 +191,7 @@ log: Or if you're not using docker, you can pass CLI arguments to the web server during startup: -``` +```bash scrutiny start --debug --log-file /tmp/web.log ``` @@ -199,14 +199,14 @@ scrutiny start --debug --log-file /tmp/web.log You can use environmental variables to enable debug logging and/or log files for the collector: -``` +```bash DEBUG=true COLLECTOR_LOG_FILE=/tmp/collector.log ``` Or if you're not using docker, you can pass CLI arguments to the collector during startup: -``` +```bash scrutiny-collector-metrics run --debug --log-file /tmp/collector.log ``` From f569ab64745b6c7b7efc12d07c0851d64a1a4c4b Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Wed, 27 Apr 2022 22:41:56 -0700 Subject: [PATCH 049/114] [BROKEN COMMIT] This code leverages the new `types.isType` functionality introduced in the flux language (https://github.com/influxdata/flux/issues/2159) This code will fix https://github.com/AnalogJ/scrutiny/issues/22 and all related issues. Unfortunately this code is broken because the influxdb go client library does not correctly handle import statments in the task defintion. blocked by https://github.com/influxdata/influxdb-client-go/issues/322 --- CONTRIBUTING.md | 6 ++- .../pkg/database/scrutiny_repository.go | 53 ++++++++++++++++--- webapp/backend/pkg/models/testdata/helper.go | 4 +- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c184ef2..da29a48 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -76,17 +76,19 @@ If you'd like to populate the database with some test data, you can run the fol > NOTE: you may need to update the `local_time` key within the JSON file, any timestamps older than ~3 weeks will be automatically ignored > (since the downsampling & retention policy takes effect at 2 weeks) +> This is done automatically by the `webapp/backend/pkg/models/testdata/helper.go` script ``` -docker run -p 8086:8086 --rm influxdb:2.0 +docker run -p 8086:8086 --rm influxdb:2.2 docker run --rm -p 8086:8086 \ + -e DOCKER_INFLUXDB_INIT_MODE=setup \ -e DOCKER_INFLUXDB_INIT_USERNAME=admin \ -e DOCKER_INFLUXDB_INIT_PASSWORD=password12345 \ -e DOCKER_INFLUXDB_INIT_ORG=scrutiny \ -e DOCKER_INFLUXDB_INIT_BUCKET=metrics \ - influxdb:2.0 + influxdb:2.2 # curl -X POST -H "Content-Type: application/json" -d @webapp/backend/pkg/web/testdata/register-devices-req.json localhost:8080/api/devices/register diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index 1a99257..cd50018 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -257,6 +257,37 @@ func (sr *scrutinyRepository) EnsureTasks(ctx context.Context, orgID string) err return nil } +/* + + +sourceBucket = "metrics" +rangeStart = -2w +rangeEnd = -1w +aggWindow = 1w +destBucket = "metrics_weekly" +destOrg = "scrutiny" + +smart_data = from(bucket: sourceBucket) +|> range(start: rangeStart, stop: rangeEnd) +|> filter(fn: (r) => r["_measurement"] == "smart" ) +|> filter(fn: (r) => r["_field"] !~ /(_measurement|device_protocol|device_wwn|attribute_id|raw_string|status_reason|when_failed)/) +|> yield(name: "last") + +smart_data +|> aggregateWindow(fn: mean, every: aggWindow) +|> to(bucket: destBucket, org: destOrg) + +temp_data = from(bucket: sourceBucket) +|> range(start: rangeStart, stop: rangeEnd) +|> filter(fn: (r) => r["_measurement"] == "temp") +|> toInt() +|> yield(name: "mean") + +temp_data +|> aggregateWindow(fn: mean, every: aggWindow) +|> to(bucket: destBucket, org: destOrg) + +*/ func (sr *scrutinyRepository) DownsampleScript(aggregationType string) string { var sourceBucket string // the source of the data var destBucket string // the destination for the aggregated data @@ -284,7 +315,7 @@ func (sr *scrutinyRepository) DownsampleScript(aggregationType string) string { aggWindow = "1y" } - return fmt.Sprintf(` + return fmt.Sprintf(`import "types" sourceBucket = "%s" rangeStart = %s rangeEnd = %s @@ -295,18 +326,24 @@ func (sr *scrutinyRepository) DownsampleScript(aggregationType string) string { smart_data = from(bucket: sourceBucket) |> range(start: rangeStart, stop: rangeEnd) |> filter(fn: (r) => r["_measurement"] == "smart" ) - |> filter(fn: (r) => r["_field"] !~ /(_measurement|device_protocol|device_wwn|attribute_id|raw_string|status_reason|when_failed)/) - |> yield(name: "last") + |> group(columns: ["device_wwn", "_field"]) - smart_data - |> aggregateWindow(fn: mean, every: aggWindow) + non_numeric_smart_data = smart_data + |> filter(fn: (r) => types.isType(v: r._value, type: "string") or types.isType(v: r._value, type: "bool")) + |> aggregateWindow(every: aggWindow, fn: last, createEmpty: false) + + numeric_smart_data = smart_data + |> filter(fn: (r) => types.isType(v: r._value, type: "int") or types.isType(v: r._value, type: "float")) + |> aggregateWindow(every: aggWindow, fn: mean, createEmpty: false) + + union(tables: [non_numeric_smart_data, numeric_smart_data]) |> to(bucket: destBucket, org: destOrg) temp_data = from(bucket: sourceBucket) |> range(start: rangeStart, stop: rangeEnd) |> filter(fn: (r) => r["_measurement"] == "temp") + |> group(columns: ["device_wwn"]) |> toInt() - |> yield(name: "mean") temp_data |> aggregateWindow(fn: mean, every: aggWindow) @@ -726,7 +763,9 @@ func (sr *scrutinyRepository) aggregateTempQuery(durationKey string) string { */ - partialQueryStr := []string{`import "influxdata/influxdb/schema"`} + partialQueryStr := []string{ + `import "influxdata/influxdb/schema"`, + } nestedDurationKeys := sr.lookupNestedDurationKeys(durationKey) diff --git a/webapp/backend/pkg/models/testdata/helper.go b/webapp/backend/pkg/models/testdata/helper.go index 559829c..771557c 100644 --- a/webapp/backend/pkg/models/testdata/helper.go +++ b/webapp/backend/pkg/models/testdata/helper.go @@ -32,7 +32,7 @@ func main() { log.Fatalf("ERROR %v", err) } defer file.Close() - _, err = SendPostRequest("http://localhost:8080/api/devices/register", file) + _, err = SendPostRequest("http://localhost:9090/api/devices/register", file) if err != nil { log.Fatalf("ERROR %v", err) } @@ -46,7 +46,7 @@ func main() { log.Fatalf("ERROR %v", err) } - _, err = SendPostRequest(fmt.Sprintf("http://localhost:8080/api/device/%s/smart", diskId), smartDataReader) + _, err = SendPostRequest(fmt.Sprintf("http://localhost:9090/api/device/%s/smart", diskId), smartDataReader) if err != nil { log.Fatalf("ERROR %v", err) } From 7a7771981a4eba78548fcf65a8703671d1f71859 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Thu, 28 Apr 2022 22:29:09 -0700 Subject: [PATCH 050/114] broke scrutiny_repository.go into multiple files for easier exploration & maintenance. --- .../pkg/database/scrutiny_repository.go | 289 +----------------- .../database/scrutiny_repository_device.go | 74 +++++ .../pkg/database/scrutiny_repository_tasks.go | 122 ++++++++ .../scrutiny_repository_temperature.go | 95 ++++++ 4 files changed, 293 insertions(+), 287 deletions(-) create mode 100644 webapp/backend/pkg/database/scrutiny_repository_device.go create mode 100644 webapp/backend/pkg/database/scrutiny_repository_tasks.go create mode 100644 webapp/backend/pkg/database/scrutiny_repository_temperature.go diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index cd50018..2ac946d 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -3,7 +3,6 @@ package database import ( "context" "fmt" - "github.com/analogj/scrutiny/webapp/backend/pkg" "github.com/analogj/scrutiny/webapp/backend/pkg/config" "github.com/analogj/scrutiny/webapp/backend/pkg/models" "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" @@ -14,7 +13,6 @@ import ( "github.com/sirupsen/logrus" "gorm.io/driver/sqlite" "gorm.io/gorm" - "gorm.io/gorm/clause" "strings" "time" ) @@ -173,8 +171,8 @@ func (sr *scrutinyRepository) EnsureBuckets(ctx context.Context, org *domain.Org var monthlyBucketRetentionRule domain.RetentionRule if sr.appConfig.GetBool("web.influxdb.retention_policy") { - // for tetsting purposes, we may not want to set a retention policy, this will allow to set data with old timestamps, - //then manually run the downsampling scripts + // in tests, we may not want to set a retention policy. If "false", we can set data with old timestamps, + // then manually run the down sampling scripts. This should be true for production environments. mainBucketRetentionRule = domain.RetentionRule{EverySeconds: RETENTION_PERIOD_15_DAYS_IN_SECONDS} weeklyBucketRetentionRule = domain.RetentionRule{EverySeconds: RETENTION_PERIOD_9_WEEKS_IN_SECONDS} monthlyBucketRetentionRule = domain.RetentionRule{EverySeconds: RETENTION_PERIOD_25_MONTHS_IN_SECONDS} @@ -224,204 +222,6 @@ func (sr *scrutinyRepository) EnsureBuckets(ctx context.Context, org *domain.Org return nil } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Tasks -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -func (sr *scrutinyRepository) EnsureTasks(ctx context.Context, orgID string) error { - weeklyTaskName := "tsk-weekly-aggr" - if found, findErr := sr.influxTaskApi.FindTasks(ctx, &api.TaskFilter{Name: weeklyTaskName}); findErr == nil && len(found) == 0 { - //weekly on Sunday at 1:00am - _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, weeklyTaskName, sr.DownsampleScript("weekly"), "0 1 * * 0", orgID) - if err != nil { - return err - } - } - - monthlyTaskName := "tsk-monthly-aggr" - if found, findErr := sr.influxTaskApi.FindTasks(ctx, &api.TaskFilter{Name: monthlyTaskName}); findErr == nil && len(found) == 0 { - //monthly on first day of the month at 1:30am - _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, monthlyTaskName, sr.DownsampleScript("monthly"), "30 1 1 * *", orgID) - if err != nil { - return err - } - } - - yearlyTaskName := "tsk-yearly-aggr" - if found, findErr := sr.influxTaskApi.FindTasks(ctx, &api.TaskFilter{Name: yearlyTaskName}); findErr == nil && len(found) == 0 { - //yearly on the first day of the year at 2:00am - _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, yearlyTaskName, sr.DownsampleScript("yearly"), "0 2 1 1 *", orgID) - if err != nil { - return err - } - } - return nil -} - -/* - - -sourceBucket = "metrics" -rangeStart = -2w -rangeEnd = -1w -aggWindow = 1w -destBucket = "metrics_weekly" -destOrg = "scrutiny" - -smart_data = from(bucket: sourceBucket) -|> range(start: rangeStart, stop: rangeEnd) -|> filter(fn: (r) => r["_measurement"] == "smart" ) -|> filter(fn: (r) => r["_field"] !~ /(_measurement|device_protocol|device_wwn|attribute_id|raw_string|status_reason|when_failed)/) -|> yield(name: "last") - -smart_data -|> aggregateWindow(fn: mean, every: aggWindow) -|> to(bucket: destBucket, org: destOrg) - -temp_data = from(bucket: sourceBucket) -|> range(start: rangeStart, stop: rangeEnd) -|> filter(fn: (r) => r["_measurement"] == "temp") -|> toInt() -|> yield(name: "mean") - -temp_data -|> aggregateWindow(fn: mean, every: aggWindow) -|> to(bucket: destBucket, org: destOrg) - -*/ -func (sr *scrutinyRepository) DownsampleScript(aggregationType string) string { - var sourceBucket string // the source of the data - var destBucket string // the destination for the aggregated data - var rangeStart string - var rangeEnd string - var aggWindow string - switch aggregationType { - case "weekly": - sourceBucket = sr.appConfig.GetString("web.influxdb.bucket") - destBucket = fmt.Sprintf("%s_weekly", sr.appConfig.GetString("web.influxdb.bucket")) - rangeStart = "-2w" - rangeEnd = "-1w" - aggWindow = "1w" - case "monthly": - sourceBucket = fmt.Sprintf("%s_weekly", sr.appConfig.GetString("web.influxdb.bucket")) - destBucket = fmt.Sprintf("%s_monthly", sr.appConfig.GetString("web.influxdb.bucket")) - rangeStart = "-2mo" - rangeEnd = "-1mo" - aggWindow = "1mo" - case "yearly": - sourceBucket = fmt.Sprintf("%s_monthly", sr.appConfig.GetString("web.influxdb.bucket")) - destBucket = fmt.Sprintf("%s_yearly", sr.appConfig.GetString("web.influxdb.bucket")) - rangeStart = "-2y" - rangeEnd = "-1y" - aggWindow = "1y" - } - - return fmt.Sprintf(`import "types" - sourceBucket = "%s" - rangeStart = %s - rangeEnd = %s - aggWindow = %s - destBucket = "%s" - destOrg = "%s" - - smart_data = from(bucket: sourceBucket) - |> range(start: rangeStart, stop: rangeEnd) - |> filter(fn: (r) => r["_measurement"] == "smart" ) - |> group(columns: ["device_wwn", "_field"]) - - non_numeric_smart_data = smart_data - |> filter(fn: (r) => types.isType(v: r._value, type: "string") or types.isType(v: r._value, type: "bool")) - |> aggregateWindow(every: aggWindow, fn: last, createEmpty: false) - - numeric_smart_data = smart_data - |> filter(fn: (r) => types.isType(v: r._value, type: "int") or types.isType(v: r._value, type: "float")) - |> aggregateWindow(every: aggWindow, fn: mean, createEmpty: false) - - union(tables: [non_numeric_smart_data, numeric_smart_data]) - |> to(bucket: destBucket, org: destOrg) - - temp_data = from(bucket: sourceBucket) - |> range(start: rangeStart, stop: rangeEnd) - |> filter(fn: (r) => r["_measurement"] == "temp") - |> group(columns: ["device_wwn"]) - |> toInt() - - temp_data - |> aggregateWindow(fn: mean, every: aggWindow) - |> to(bucket: destBucket, org: destOrg) - `, - sourceBucket, - rangeStart, - rangeEnd, - aggWindow, - destBucket, - sr.appConfig.GetString("web.influxdb.org"), - ) -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Device -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -//insert device into DB (and update specified columns if device is already registered) -// update device fields that may change: (DeviceType, HostID) -func (sr *scrutinyRepository) RegisterDevice(ctx context.Context, dev models.Device) error { - if err := sr.gormClient.WithContext(ctx).Clauses(clause.OnConflict{ - Columns: []clause.Column{{Name: "wwn"}}, - DoUpdates: clause.AssignmentColumns([]string{"host_id", "device_name", "device_type"}), - }).Create(&dev).Error; err != nil { - return err - } - return nil -} - -// get a list of all devices (only device metadata, no SMART data) -func (sr *scrutinyRepository) GetDevices(ctx context.Context) ([]models.Device, error) { - //Get a list of all the active devices. - devices := []models.Device{} - if err := sr.gormClient.WithContext(ctx).Find(&devices).Error; err != nil { - return nil, fmt.Errorf("Could not get device summary from DB: %v", err) - } - return devices, nil -} - -// update device (only metadata) from collector -func (sr *scrutinyRepository) UpdateDevice(ctx context.Context, wwn string, collectorSmartData collector.SmartInfo) (models.Device, error) { - var device models.Device - if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil { - return device, fmt.Errorf("Could not get device from DB: %v", err) - } - - //TODO catch GormClient err - err := device.UpdateFromCollectorSmartInfo(collectorSmartData) - if err != nil { - return device, err - } - return device, sr.gormClient.Model(&device).Updates(device).Error -} - -//Update Device Status -func (sr *scrutinyRepository) UpdateDeviceStatus(ctx context.Context, wwn string, status pkg.DeviceStatus) (models.Device, error) { - var device models.Device - if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil { - return device, fmt.Errorf("Could not get device from DB: %v", err) - } - - device.DeviceStatus = pkg.Set(device.DeviceStatus, status) - return device, sr.gormClient.Model(&device).Updates(device).Error -} - -func (sr *scrutinyRepository) GetDeviceDetails(ctx context.Context, wwn string) (models.Device, error) { - var device models.Device - - fmt.Println("GetDeviceDetails from GORM") - - if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil { - return models.Device{}, err - } - - return device, nil -} - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // SMART //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -512,91 +312,6 @@ func (sr *scrutinyRepository) GetSmartAttributeHistory(ctx context.Context, wwn } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Temperature Data -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -func (sr *scrutinyRepository) SaveSmartTemperature(ctx context.Context, wwn string, deviceProtocol string, collectorSmartData collector.SmartInfo) error { - if len(collectorSmartData.AtaSctTemperatureHistory.Table) > 0 { - - for ndx, temp := range collectorSmartData.AtaSctTemperatureHistory.Table { - - minutesOffset := collectorSmartData.AtaSctTemperatureHistory.LoggingIntervalMinutes * int64(ndx) * 60 - smartTemp := measurements.SmartTemperature{ - Date: time.Unix(collectorSmartData.LocalTime.TimeT-minutesOffset, 0), - Temp: temp, - } - - tags, fields := smartTemp.Flatten() - tags["device_wwn"] = wwn - p := influxdb2.NewPoint("temp", - tags, - fields, - smartTemp.Date) - err := sr.influxWriteApi.WritePoint(ctx, p) - if err != nil { - return err - } - } - // also add the current temperature. - } else { - - smartTemp := measurements.SmartTemperature{ - Date: time.Unix(collectorSmartData.LocalTime.TimeT, 0), - Temp: collectorSmartData.Temperature.Current, - } - - tags, fields := smartTemp.Flatten() - tags["device_wwn"] = wwn - p := influxdb2.NewPoint("temp", - tags, - fields, - smartTemp.Date) - return sr.influxWriteApi.WritePoint(ctx, p) - } - return nil -} - -func (sr *scrutinyRepository) GetSmartTemperatureHistory(ctx context.Context, durationKey string) (map[string][]measurements.SmartTemperature, error) { - //we can get temp history for "week", "month", DURATION_KEY_YEAR, "forever" - - deviceTempHistory := map[string][]measurements.SmartTemperature{} - - //TODO: change the query range to a variable. - queryStr := sr.aggregateTempQuery(durationKey) - - result, err := sr.influxQueryApi.Query(ctx, queryStr) - if err == nil { - // Use Next() to iterate over query result lines - for result.Next() { - - if deviceWWN, ok := result.Record().Values()["device_wwn"]; ok { - - //check if deviceWWN has been seen and initialized already - if _, ok := deviceTempHistory[deviceWWN.(string)]; !ok { - deviceTempHistory[deviceWWN.(string)] = []measurements.SmartTemperature{} - } - - currentTempHistory := deviceTempHistory[deviceWWN.(string)] - smartTemp := measurements.SmartTemperature{} - - for key, val := range result.Record().Values() { - smartTemp.Inflate(key, val) - } - smartTemp.Date = result.Record().Values()["_time"].(time.Time) - currentTempHistory = append(currentTempHistory, smartTemp) - deviceTempHistory[deviceWWN.(string)] = currentTempHistory - } - } - if result.Err() != nil { - fmt.Printf("Query error: %s\n", result.Err().Error()) - } - } else { - return nil, err - } - return deviceTempHistory, nil - -} - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // DeviceSummary //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/webapp/backend/pkg/database/scrutiny_repository_device.go b/webapp/backend/pkg/database/scrutiny_repository_device.go new file mode 100644 index 0000000..27346f3 --- /dev/null +++ b/webapp/backend/pkg/database/scrutiny_repository_device.go @@ -0,0 +1,74 @@ +package database + +import ( + "context" + "fmt" + "github.com/analogj/scrutiny/webapp/backend/pkg" + "github.com/analogj/scrutiny/webapp/backend/pkg/models" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" + "gorm.io/gorm/clause" +) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Device +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//insert device into DB (and update specified columns if device is already registered) +// update device fields that may change: (DeviceType, HostID) +func (sr *scrutinyRepository) RegisterDevice(ctx context.Context, dev models.Device) error { + if err := sr.gormClient.WithContext(ctx).Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "wwn"}}, + DoUpdates: clause.AssignmentColumns([]string{"host_id", "device_name", "device_type"}), + }).Create(&dev).Error; err != nil { + return err + } + return nil +} + +// get a list of all devices (only device metadata, no SMART data) +func (sr *scrutinyRepository) GetDevices(ctx context.Context) ([]models.Device, error) { + //Get a list of all the active devices. + devices := []models.Device{} + if err := sr.gormClient.WithContext(ctx).Find(&devices).Error; err != nil { + return nil, fmt.Errorf("Could not get device summary from DB: %v", err) + } + return devices, nil +} + +// update device (only metadata) from collector +func (sr *scrutinyRepository) UpdateDevice(ctx context.Context, wwn string, collectorSmartData collector.SmartInfo) (models.Device, error) { + var device models.Device + if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil { + return device, fmt.Errorf("Could not get device from DB: %v", err) + } + + //TODO catch GormClient err + err := device.UpdateFromCollectorSmartInfo(collectorSmartData) + if err != nil { + return device, err + } + return device, sr.gormClient.Model(&device).Updates(device).Error +} + +//Update Device Status +func (sr *scrutinyRepository) UpdateDeviceStatus(ctx context.Context, wwn string, status pkg.DeviceStatus) (models.Device, error) { + var device models.Device + if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil { + return device, fmt.Errorf("Could not get device from DB: %v", err) + } + + device.DeviceStatus = pkg.Set(device.DeviceStatus, status) + return device, sr.gormClient.Model(&device).Updates(device).Error +} + +func (sr *scrutinyRepository) GetDeviceDetails(ctx context.Context, wwn string) (models.Device, error) { + var device models.Device + + fmt.Println("GetDeviceDetails from GORM") + + if err := sr.gormClient.WithContext(ctx).Where("wwn = ?", wwn).First(&device).Error; err != nil { + return models.Device{}, err + } + + return device, nil +} diff --git a/webapp/backend/pkg/database/scrutiny_repository_tasks.go b/webapp/backend/pkg/database/scrutiny_repository_tasks.go new file mode 100644 index 0000000..b7f487a --- /dev/null +++ b/webapp/backend/pkg/database/scrutiny_repository_tasks.go @@ -0,0 +1,122 @@ +package database + +import ( + "context" + "fmt" + "github.com/influxdata/influxdb-client-go/v2/api" +) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Tasks +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +func (sr *scrutinyRepository) EnsureTasks(ctx context.Context, orgID string) error { + weeklyTaskName := "tsk-weekly-aggr" + if found, findErr := sr.influxTaskApi.FindTasks(ctx, &api.TaskFilter{Name: weeklyTaskName}); findErr == nil && len(found) == 0 { + //weekly on Sunday at 1:00am + _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, weeklyTaskName, sr.DownsampleScript("weekly"), "0 1 * * 0", orgID) + if err != nil { + return err + } + } + + monthlyTaskName := "tsk-monthly-aggr" + if found, findErr := sr.influxTaskApi.FindTasks(ctx, &api.TaskFilter{Name: monthlyTaskName}); findErr == nil && len(found) == 0 { + //monthly on first day of the month at 1:30am + _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, monthlyTaskName, sr.DownsampleScript("monthly"), "30 1 1 * *", orgID) + if err != nil { + return err + } + } + + yearlyTaskName := "tsk-yearly-aggr" + if found, findErr := sr.influxTaskApi.FindTasks(ctx, &api.TaskFilter{Name: yearlyTaskName}); findErr == nil && len(found) == 0 { + //yearly on the first day of the year at 2:00am + _, err := sr.influxTaskApi.CreateTaskWithCron(ctx, yearlyTaskName, sr.DownsampleScript("yearly"), "0 2 1 1 *", orgID) + if err != nil { + return err + } + } + return nil +} + +func (sr *scrutinyRepository) DownsampleScript(aggregationType string) string { + var sourceBucket string // the source of the data + var destBucket string // the destination for the aggregated data + var rangeStart string + var rangeEnd string + var aggWindow string + switch aggregationType { + case "weekly": + sourceBucket = sr.appConfig.GetString("web.influxdb.bucket") + destBucket = fmt.Sprintf("%s_weekly", sr.appConfig.GetString("web.influxdb.bucket")) + rangeStart = "-2w" + rangeEnd = "-1w" + aggWindow = "1w" + case "monthly": + sourceBucket = fmt.Sprintf("%s_weekly", sr.appConfig.GetString("web.influxdb.bucket")) + destBucket = fmt.Sprintf("%s_monthly", sr.appConfig.GetString("web.influxdb.bucket")) + rangeStart = "-2mo" + rangeEnd = "-1mo" + aggWindow = "1mo" + case "yearly": + sourceBucket = fmt.Sprintf("%s_monthly", sr.appConfig.GetString("web.influxdb.bucket")) + destBucket = fmt.Sprintf("%s_yearly", sr.appConfig.GetString("web.influxdb.bucket")) + rangeStart = "-2y" + rangeEnd = "-1y" + aggWindow = "1y" + } + + // TODO: using "last" function for aggregation. This should eventually be replaced with a more accurate represenation + /* + import "types" + smart_data = from(bucket: sourceBucket) + |> range(start: rangeStart, stop: rangeEnd) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> group(columns: ["device_wwn", "_field"]) + + non_numeric_smart_data = smart_data + |> filter(fn: (r) => types.isType(v: r._value, type: "string") or types.isType(v: r._value, type: "bool")) + |> aggregateWindow(every: aggWindow, fn: last, createEmpty: false) + + numeric_smart_data = smart_data + |> filter(fn: (r) => types.isType(v: r._value, type: "int") or types.isType(v: r._value, type: "float")) + |> aggregateWindow(every: aggWindow, fn: mean, createEmpty: false) + + union(tables: [non_numeric_smart_data, numeric_smart_data]) + |> to(bucket: destBucket, org: destOrg) + + */ + + return fmt.Sprintf(` + sourceBucket = "%s" + rangeStart = %s + rangeEnd = %s + aggWindow = %s + destBucket = "%s" + destOrg = "%s" + + from(bucket: sourceBucket) + |> range(start: rangeStart, stop: rangeEnd) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> group(columns: ["device_wwn", "_field"]) + |> aggregateWindow(every: aggWindow, fn: last, createEmpty: false) + |> to(bucket: destBucket, org: destOrg) + + temp_data = from(bucket: sourceBucket) + |> range(start: rangeStart, stop: rangeEnd) + |> filter(fn: (r) => r["_measurement"] == "temp") + |> group(columns: ["device_wwn"]) + |> toInt() + + temp_data + |> aggregateWindow(fn: mean, every: aggWindow) + |> to(bucket: destBucket, org: destOrg) + `, + sourceBucket, + rangeStart, + rangeEnd, + aggWindow, + destBucket, + sr.appConfig.GetString("web.influxdb.org"), + ) +} diff --git a/webapp/backend/pkg/database/scrutiny_repository_temperature.go b/webapp/backend/pkg/database/scrutiny_repository_temperature.go new file mode 100644 index 0000000..574ca2c --- /dev/null +++ b/webapp/backend/pkg/database/scrutiny_repository_temperature.go @@ -0,0 +1,95 @@ +package database + +import ( + "context" + "fmt" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" + influxdb2 "github.com/influxdata/influxdb-client-go/v2" + "time" +) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Temperature Data +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +func (sr *scrutinyRepository) SaveSmartTemperature(ctx context.Context, wwn string, deviceProtocol string, collectorSmartData collector.SmartInfo) error { + if len(collectorSmartData.AtaSctTemperatureHistory.Table) > 0 { + + for ndx, temp := range collectorSmartData.AtaSctTemperatureHistory.Table { + + minutesOffset := collectorSmartData.AtaSctTemperatureHistory.LoggingIntervalMinutes * int64(ndx) * 60 + smartTemp := measurements.SmartTemperature{ + Date: time.Unix(collectorSmartData.LocalTime.TimeT-minutesOffset, 0), + Temp: temp, + } + + tags, fields := smartTemp.Flatten() + tags["device_wwn"] = wwn + p := influxdb2.NewPoint("temp", + tags, + fields, + smartTemp.Date) + err := sr.influxWriteApi.WritePoint(ctx, p) + if err != nil { + return err + } + } + // also add the current temperature. + } else { + + smartTemp := measurements.SmartTemperature{ + Date: time.Unix(collectorSmartData.LocalTime.TimeT, 0), + Temp: collectorSmartData.Temperature.Current, + } + + tags, fields := smartTemp.Flatten() + tags["device_wwn"] = wwn + p := influxdb2.NewPoint("temp", + tags, + fields, + smartTemp.Date) + return sr.influxWriteApi.WritePoint(ctx, p) + } + return nil +} + +func (sr *scrutinyRepository) GetSmartTemperatureHistory(ctx context.Context, durationKey string) (map[string][]measurements.SmartTemperature, error) { + //we can get temp history for "week", "month", DURATION_KEY_YEAR, "forever" + + deviceTempHistory := map[string][]measurements.SmartTemperature{} + + //TODO: change the query range to a variable. + queryStr := sr.aggregateTempQuery(durationKey) + + result, err := sr.influxQueryApi.Query(ctx, queryStr) + if err == nil { + // Use Next() to iterate over query result lines + for result.Next() { + + if deviceWWN, ok := result.Record().Values()["device_wwn"]; ok { + + //check if deviceWWN has been seen and initialized already + if _, ok := deviceTempHistory[deviceWWN.(string)]; !ok { + deviceTempHistory[deviceWWN.(string)] = []measurements.SmartTemperature{} + } + + currentTempHistory := deviceTempHistory[deviceWWN.(string)] + smartTemp := measurements.SmartTemperature{} + + for key, val := range result.Record().Values() { + smartTemp.Inflate(key, val) + } + smartTemp.Date = result.Record().Values()["_time"].(time.Time) + currentTempHistory = append(currentTempHistory, smartTemp) + deviceTempHistory[deviceWWN.(string)] = currentTempHistory + } + } + if result.Err() != nil { + fmt.Printf("Query error: %s\n", result.Err().Error()) + } + } else { + return nil, err + } + return deviceTempHistory, nil + +} From f60636a6aa12ca446ca473f93ca67362c8cc2aa5 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Thu, 28 Apr 2022 22:33:09 -0700 Subject: [PATCH 051/114] broke scrutiny_repository.go into multiple files for easier exploration & maintenance. --- .../pkg/database/scrutiny_repository.go | 68 ------------------ .../scrutiny_repository_temperature.go | 72 +++++++++++++++++++ 2 files changed, 72 insertions(+), 68 deletions(-) diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index 2ac946d..5d3ca51 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -13,7 +13,6 @@ import ( "github.com/sirupsen/logrus" "gorm.io/driver/sqlite" "gorm.io/gorm" - "strings" "time" ) @@ -452,70 +451,3 @@ func (sr *scrutinyRepository) lookupNestedDurationKeys(durationKey string) []str } return []string{DURATION_KEY_WEEK} } - -func (sr *scrutinyRepository) aggregateTempQuery(durationKey string) string { - - /* - import "influxdata/influxdb/schema" - weekData = from(bucket: "metrics") - |> range(start: -1w, stop: now()) - |> filter(fn: (r) => r["_measurement"] == "temp" ) - |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) - |> group(columns: ["device_wwn"]) - |> toInt() - - monthData = from(bucket: "metrics_weekly") - |> range(start: -1mo, stop: now()) - |> filter(fn: (r) => r["_measurement"] == "temp" ) - |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) - |> group(columns: ["device_wwn"]) - |> toInt() - - union(tables: [weekData, monthData]) - |> group(columns: ["device_wwn"]) - |> sort(columns: ["_time"], desc: false) - |> schema.fieldsAsCols() - - */ - - partialQueryStr := []string{ - `import "influxdata/influxdb/schema"`, - } - - nestedDurationKeys := sr.lookupNestedDurationKeys(durationKey) - - subQueryNames := []string{} - for _, nestedDurationKey := range nestedDurationKeys { - bucketName := sr.lookupBucketName(nestedDurationKey) - durationRange := sr.lookupDuration(nestedDurationKey) - - subQueryNames = append(subQueryNames, fmt.Sprintf(`%sData`, nestedDurationKey)) - partialQueryStr = append(partialQueryStr, []string{ - fmt.Sprintf(`%sData = from(bucket: "%s")`, nestedDurationKey, bucketName), - fmt.Sprintf(`|> range(start: %s, stop: %s)`, durationRange[0], durationRange[1]), - `|> filter(fn: (r) => r["_measurement"] == "temp" )`, - `|> aggregateWindow(every: 1h, fn: mean, createEmpty: false)`, - `|> group(columns: ["device_wwn"])`, - `|> toInt()`, - "", - }...) - } - - if len(subQueryNames) == 1 { - //there's only one bucket being queried, no need to union, just aggregate the dataset and return - partialQueryStr = append(partialQueryStr, []string{ - subQueryNames[0], - "|> schema.fieldsAsCols()", - "|> yield()", - }...) - } else { - partialQueryStr = append(partialQueryStr, []string{ - fmt.Sprintf("union(tables: [%s])", strings.Join(subQueryNames, ", ")), - `|> group(columns: ["device_wwn"])`, - `|> sort(columns: ["_time"], desc: false)`, - "|> schema.fieldsAsCols()", - }...) - } - - return strings.Join(partialQueryStr, "\n") -} diff --git a/webapp/backend/pkg/database/scrutiny_repository_temperature.go b/webapp/backend/pkg/database/scrutiny_repository_temperature.go index 574ca2c..fb3be6a 100644 --- a/webapp/backend/pkg/database/scrutiny_repository_temperature.go +++ b/webapp/backend/pkg/database/scrutiny_repository_temperature.go @@ -6,6 +6,7 @@ import ( "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" influxdb2 "github.com/influxdata/influxdb-client-go/v2" + "strings" "time" ) @@ -93,3 +94,74 @@ func (sr *scrutinyRepository) GetSmartTemperatureHistory(ctx context.Context, du return deviceTempHistory, nil } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Helper Methods +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +func (sr *scrutinyRepository) aggregateTempQuery(durationKey string) string { + + /* + import "influxdata/influxdb/schema" + weekData = from(bucket: "metrics") + |> range(start: -1w, stop: now()) + |> filter(fn: (r) => r["_measurement"] == "temp" ) + |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) + |> group(columns: ["device_wwn"]) + |> toInt() + + monthData = from(bucket: "metrics_weekly") + |> range(start: -1mo, stop: now()) + |> filter(fn: (r) => r["_measurement"] == "temp" ) + |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) + |> group(columns: ["device_wwn"]) + |> toInt() + + union(tables: [weekData, monthData]) + |> group(columns: ["device_wwn"]) + |> sort(columns: ["_time"], desc: false) + |> schema.fieldsAsCols() + + */ + + partialQueryStr := []string{ + `import "influxdata/influxdb/schema"`, + } + + nestedDurationKeys := sr.lookupNestedDurationKeys(durationKey) + + subQueryNames := []string{} + for _, nestedDurationKey := range nestedDurationKeys { + bucketName := sr.lookupBucketName(nestedDurationKey) + durationRange := sr.lookupDuration(nestedDurationKey) + + subQueryNames = append(subQueryNames, fmt.Sprintf(`%sData`, nestedDurationKey)) + partialQueryStr = append(partialQueryStr, []string{ + fmt.Sprintf(`%sData = from(bucket: "%s")`, nestedDurationKey, bucketName), + fmt.Sprintf(`|> range(start: %s, stop: %s)`, durationRange[0], durationRange[1]), + `|> filter(fn: (r) => r["_measurement"] == "temp" )`, + `|> aggregateWindow(every: 1h, fn: mean, createEmpty: false)`, + `|> group(columns: ["device_wwn"])`, + `|> toInt()`, + "", + }...) + } + + if len(subQueryNames) == 1 { + //there's only one bucket being queried, no need to union, just aggregate the dataset and return + partialQueryStr = append(partialQueryStr, []string{ + subQueryNames[0], + "|> schema.fieldsAsCols()", + "|> yield()", + }...) + } else { + partialQueryStr = append(partialQueryStr, []string{ + fmt.Sprintf("union(tables: [%s])", strings.Join(subQueryNames, ", ")), + `|> group(columns: ["device_wwn"])`, + `|> sort(columns: ["_time"], desc: false)`, + "|> schema.fieldsAsCols()", + }...) + } + + return strings.Join(partialQueryStr, "\n") +} From 0a9d364aea4ba4efa1211de41be06379cb7c64b5 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 29 Apr 2022 15:26:15 -0700 Subject: [PATCH 052/114] adding duration key to smart attributes api endpoint --- webapp/backend/pkg/database/interface.go | 2 +- .../pkg/database/scrutiny_repository.go | 92 ---------- ...tiny_repository_device_smart_attributes.go | 163 ++++++++++++++++++ .../pkg/web/handler/get_device_details.go | 12 +- 4 files changed, 175 insertions(+), 94 deletions(-) create mode 100644 webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go diff --git a/webapp/backend/pkg/database/interface.go b/webapp/backend/pkg/database/interface.go index 9e50596..2d4eba4 100644 --- a/webapp/backend/pkg/database/interface.go +++ b/webapp/backend/pkg/database/interface.go @@ -21,7 +21,7 @@ type DeviceRepo interface { GetDeviceDetails(ctx context.Context, wwn string) (models.Device, error) SaveSmartAttributes(ctx context.Context, wwn string, collectorSmartData collector.SmartInfo) (measurements.Smart, error) - GetSmartAttributeHistory(ctx context.Context, wwn string, startAt string, attributes []string) ([]measurements.Smart, error) + GetSmartAttributeHistory(ctx context.Context, wwn string, durationKey string, attributes []string) ([]measurements.Smart, error) SaveSmartTemperature(ctx context.Context, wwn string, deviceProtocol string, collectorSmartData collector.SmartInfo) error diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index 5d3ca51..0102771 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -5,8 +5,6 @@ import ( "fmt" "github.com/analogj/scrutiny/webapp/backend/pkg/config" "github.com/analogj/scrutiny/webapp/backend/pkg/models" - "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" - "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" influxdb2 "github.com/influxdata/influxdb-client-go/v2" "github.com/influxdata/influxdb-client-go/v2/api" "github.com/influxdata/influxdb-client-go/v2/domain" @@ -221,96 +219,6 @@ func (sr *scrutinyRepository) EnsureBuckets(ctx context.Context, org *domain.Org return nil } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// SMART -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -func (sr *scrutinyRepository) SaveSmartAttributes(ctx context.Context, wwn string, collectorSmartData collector.SmartInfo) (measurements.Smart, error) { - deviceSmartData := measurements.Smart{} - err := deviceSmartData.FromCollectorSmartInfo(wwn, collectorSmartData) - if err != nil { - sr.logger.Errorln("Could not process SMART metrics", err) - return measurements.Smart{}, err - } - - tags, fields := deviceSmartData.Flatten() - p := influxdb2.NewPoint("smart", - tags, - fields, - deviceSmartData.Date) - - // write point immediately - return deviceSmartData, sr.influxWriteApi.WritePoint(ctx, p) -} - -func (sr *scrutinyRepository) GetSmartAttributeHistory(ctx context.Context, wwn string, startAt string, attributes []string) ([]measurements.Smart, error) { - // Get SMartResults from InfluxDB - - fmt.Println("GetDeviceDetails from INFLUXDB") - - //TODO: change the filter startrange to a real number. - - // Get parser flux query result - //appConfig.GetString("web.influxdb.bucket") - queryStr := fmt.Sprintf(` - import "influxdata/influxdb/schema" - from(bucket: "%s") - |> range(start: -2y, stop: now()) - |> filter(fn: (r) => r["_measurement"] == "smart" ) - |> filter(fn: (r) => r["device_wwn"] == "%s" ) - |> schema.fieldsAsCols() - |> group(columns: ["device_wwn"]) - |> yield(name: "last") - `, - sr.appConfig.GetString("web.influxdb.bucket"), - wwn, - ) - - smartResults := []measurements.Smart{} - - result, err := sr.influxQueryApi.Query(ctx, queryStr) - if err == nil { - fmt.Println("GetDeviceDetails NO EROR") - - // Use Next() to iterate over query result lines - for result.Next() { - fmt.Println("GetDeviceDetails NEXT") - - // Observe when there is new grouping key producing new table - if result.TableChanged() { - //fmt.Printf("table: %s\n", result.TableMetadata().String()) - } - - fmt.Printf("DECODINIG TABLE VALUES: %v", result.Record().Values()) - smartData, err := measurements.NewSmartFromInfluxDB(result.Record().Values()) - if err != nil { - return nil, err - } - smartResults = append(smartResults, *smartData) - - } - if result.Err() != nil { - fmt.Printf("Query error: %s\n", result.Err().Error()) - } - } else { - return nil, err - } - - return smartResults, nil - - //if err := device.SquashHistory(); err != nil { - // logger.Errorln("An error occurred while squashing device history", err) - // c.JSON(http.StatusInternalServerError, gin.H{"success": false}) - // return - //} - // - //if err := device.ApplyMetadataRules(); err != nil { - // logger.Errorln("An error occurred while applying scrutiny thresholds & rules", err) - // c.JSON(http.StatusInternalServerError, gin.H{"success": false}) - // return - //} - -} - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // DeviceSummary //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go b/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go new file mode 100644 index 0000000..ab1608e --- /dev/null +++ b/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go @@ -0,0 +1,163 @@ +package database + +import ( + "context" + "fmt" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" + influxdb2 "github.com/influxdata/influxdb-client-go/v2" + "strings" +) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SMART +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +func (sr *scrutinyRepository) SaveSmartAttributes(ctx context.Context, wwn string, collectorSmartData collector.SmartInfo) (measurements.Smart, error) { + deviceSmartData := measurements.Smart{} + err := deviceSmartData.FromCollectorSmartInfo(wwn, collectorSmartData) + if err != nil { + sr.logger.Errorln("Could not process SMART metrics", err) + return measurements.Smart{}, err + } + + tags, fields := deviceSmartData.Flatten() + p := influxdb2.NewPoint("smart", + tags, + fields, + deviceSmartData.Date) + + // write point immediately + return deviceSmartData, sr.influxWriteApi.WritePoint(ctx, p) +} + +func (sr *scrutinyRepository) GetSmartAttributeHistory(ctx context.Context, wwn string, durationKey string, attributes []string) ([]measurements.Smart, error) { + // Get SMartResults from InfluxDB + + fmt.Println("GetDeviceDetails from INFLUXDB") + + //TODO: change the filter startrange to a real number. + + // Get parser flux query result + //appConfig.GetString("web.influxdb.bucket") + queryStr := sr.aggregateSmartAttributesQuery(wwn, durationKey) + + smartResults := []measurements.Smart{} + + result, err := sr.influxQueryApi.Query(ctx, queryStr) + if err == nil { + fmt.Println("GetDeviceDetails NO EROR") + + // Use Next() to iterate over query result lines + for result.Next() { + fmt.Println("GetDeviceDetails NEXT") + + // Observe when there is new grouping key producing new table + if result.TableChanged() { + //fmt.Printf("table: %s\n", result.TableMetadata().String()) + } + + fmt.Printf("DECODINIG TABLE VALUES: %v", result.Record().Values()) + smartData, err := measurements.NewSmartFromInfluxDB(result.Record().Values()) + if err != nil { + return nil, err + } + smartResults = append(smartResults, *smartData) + + } + if result.Err() != nil { + fmt.Printf("Query error: %s\n", result.Err().Error()) + } + } else { + return nil, err + } + + return smartResults, nil + + //if err := device.SquashHistory(); err != nil { + // logger.Errorln("An error occurred while squashing device history", err) + // c.JSON(http.StatusInternalServerError, gin.H{"success": false}) + // return + //} + // + //if err := device.ApplyMetadataRules(); err != nil { + // logger.Errorln("An error occurred while applying scrutiny thresholds & rules", err) + // c.JSON(http.StatusInternalServerError, gin.H{"success": false}) + // return + //} + +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Helper Methods +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +func (sr *scrutinyRepository) aggregateSmartAttributesQuery(wwn string, durationKey string) string { + + /* + + import "influxdata/influxdb/schema" + weekData = from(bucket: "metrics") + |> range(start: -1w, stop: now()) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> filter(fn: (r) => r["device_wwn"] == "%s" ) + |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) + |> group(columns: ["device_wwn"]) + |> toInt() + + monthData = from(bucket: "metrics_weekly") + |> range(start: -1mo, stop: now()) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> filter(fn: (r) => r["device_wwn"] == "%s" ) + |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) + |> group(columns: ["device_wwn"]) + |> toInt() + + union(tables: [weekData, monthData]) + |> group(columns: ["device_wwn"]) + |> sort(columns: ["_time"], desc: false) + |> schema.fieldsAsCols() + + */ + + partialQueryStr := []string{ + `import "influxdata/influxdb/schema"`, + } + + nestedDurationKeys := sr.lookupNestedDurationKeys(durationKey) + + subQueryNames := []string{} + for _, nestedDurationKey := range nestedDurationKeys { + bucketName := sr.lookupBucketName(nestedDurationKey) + durationRange := sr.lookupDuration(nestedDurationKey) + + subQueryNames = append(subQueryNames, fmt.Sprintf(`%sData`, nestedDurationKey)) + partialQueryStr = append(partialQueryStr, []string{ + fmt.Sprintf(`%sData = from(bucket: "%s")`, nestedDurationKey, bucketName), + fmt.Sprintf(`|> range(start: %s, stop: %s)`, durationRange[0], durationRange[1]), + `|> filter(fn: (r) => r["_measurement"] == "smart" )`, + fmt.Sprintf(`|> filter(fn: (r) => r["device_wwn"] == "%s" )`, wwn), + `|> aggregateWindow(every: 1h, fn: last, createEmpty: false)`, + `|> group(columns: ["device_wwn"])`, + `|> toInt()`, + "", + }...) + } + + if len(subQueryNames) == 1 { + //there's only one bucket being queried, no need to union, just aggregate the dataset and return + partialQueryStr = append(partialQueryStr, []string{ + subQueryNames[0], + "|> schema.fieldsAsCols()", + "|> yield()", + }...) + } else { + partialQueryStr = append(partialQueryStr, []string{ + fmt.Sprintf("union(tables: [%s])", strings.Join(subQueryNames, ", ")), + `|> group(columns: ["device_wwn"])`, + `|> sort(columns: ["_time"], desc: false)`, + "|> schema.fieldsAsCols()", + }...) + } + + return strings.Join(partialQueryStr, "\n") +} diff --git a/webapp/backend/pkg/web/handler/get_device_details.go b/webapp/backend/pkg/web/handler/get_device_details.go index d938c88..864b842 100644 --- a/webapp/backend/pkg/web/handler/get_device_details.go +++ b/webapp/backend/pkg/web/handler/get_device_details.go @@ -19,7 +19,17 @@ func GetDeviceDetails(c *gin.Context) { return } - smartResults, err := deviceRepo.GetSmartAttributeHistory(c, c.Param("wwn"), "", nil) + durationKey, exists := c.GetQuery("duration_key") + if !exists { + durationKey = "forever" + } + + smartResults, err := deviceRepo.GetSmartAttributeHistory(c, c.Param("wwn"), durationKey, nil) + if err != nil { + logger.Errorln("An error occurred while retrieving device smart results", err) + c.JSON(http.StatusInternalServerError, gin.H{"success": false}) + return + } var deviceMetadata interface{} if device.IsAta() { From bd39b2cd4d272cfbc1699c6fc7e2e58c18ac18d7 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 29 Apr 2022 16:11:12 -0700 Subject: [PATCH 053/114] fixes for aggregation. --- .../scrutiny_repository_device_smart_attributes.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go b/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go index ab1608e..263e08d 100644 --- a/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go +++ b/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go @@ -6,6 +6,7 @@ import ( "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" influxdb2 "github.com/influxdata/influxdb-client-go/v2" + log "github.com/sirupsen/logrus" "strings" ) @@ -40,6 +41,7 @@ func (sr *scrutinyRepository) GetSmartAttributeHistory(ctx context.Context, wwn // Get parser flux query result //appConfig.GetString("web.influxdb.bucket") queryStr := sr.aggregateSmartAttributesQuery(wwn, durationKey) + log.Infoln(queryStr) smartResults := []measurements.Smart{} @@ -136,10 +138,7 @@ func (sr *scrutinyRepository) aggregateSmartAttributesQuery(wwn string, duration fmt.Sprintf(`|> range(start: %s, stop: %s)`, durationRange[0], durationRange[1]), `|> filter(fn: (r) => r["_measurement"] == "smart" )`, fmt.Sprintf(`|> filter(fn: (r) => r["device_wwn"] == "%s" )`, wwn), - `|> aggregateWindow(every: 1h, fn: last, createEmpty: false)`, - `|> group(columns: ["device_wwn"])`, - `|> toInt()`, - "", + "|> schema.fieldsAsCols()", }...) } @@ -147,15 +146,13 @@ func (sr *scrutinyRepository) aggregateSmartAttributesQuery(wwn string, duration //there's only one bucket being queried, no need to union, just aggregate the dataset and return partialQueryStr = append(partialQueryStr, []string{ subQueryNames[0], - "|> schema.fieldsAsCols()", - "|> yield()", + `|> yield()`, }...) } else { partialQueryStr = append(partialQueryStr, []string{ fmt.Sprintf("union(tables: [%s])", strings.Join(subQueryNames, ", ")), - `|> group(columns: ["device_wwn"])`, `|> sort(columns: ["_time"], desc: false)`, - "|> schema.fieldsAsCols()", + `|> yield(name: "last")`, }...) } From 7cd828ef0d74d04e06bf6f53bae1a55af14a3ed3 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 29 Apr 2022 16:20:35 -0700 Subject: [PATCH 054/114] update the influxdb version in the standalone container. --- docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 235ff60..d1bda0c 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -37,8 +37,8 @@ RUN apt-get update && apt-get install -y cron smartmontools=7.0-0ubuntu1~ubuntu1 ADD https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s6-overlay-amd64.tar.gz /tmp/ RUN tar xzf /tmp/s6-overlay-amd64.tar.gz -C / -ADD https://dl.influxdata.com/influxdb/releases/influxdb2-2.0.4-amd64.deb /tmp/ -RUN dpkg -i /tmp/influxdb2-2.0.4-amd64.deb && rm -rf /tmp/influxdb2-2.0.4-amd64.deb +ADD https://dl.influxdata.com/influxdb/releases/influxdb2-2.2.0-amd64.deb /tmp/ +RUN dpkg -i /tmp/influxdb2-2.2.0-amd64.deb && rm -rf /tmp/influxdb2-2.2.0-amd64.deb COPY /rootfs / From 00bc6ecd92bdc9307712805f268c9fcf72798701 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 29 Apr 2022 16:28:50 -0700 Subject: [PATCH 055/114] make sure we can pull config from env variables. --- .github/workflows/build.yaml | 1 + webapp/backend/pkg/config/config.go | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 14ad185..064b177 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -24,6 +24,7 @@ jobs: env: PROJECT_PATH: /go/src/github.com/analogj/scrutiny CGO_ENABLED: 1 + SCRUTINY_WEB_INFLUXDB_HOST: influxdb steps: - name: Git run: | diff --git a/webapp/backend/pkg/config/config.go b/webapp/backend/pkg/config/config.go index 27e1c05..31243e9 100644 --- a/webapp/backend/pkg/config/config.go +++ b/webapp/backend/pkg/config/config.go @@ -6,6 +6,7 @@ import ( "github.com/spf13/viper" "log" "os" + "strings" ) // When initializing this class the following methods must be called: @@ -64,6 +65,11 @@ func (c *configuration) Init() error { //c.SetConfigName("drawbridge") //c.AddConfigPath("$HOME/") + //configure env variable parsing. + c.SetEnvPrefix("SCRUTINY") + c.SetEnvKeyReplacer(strings.NewReplacer("-", "_", ".", "_")) + c.AutomaticEnv() + //CLI options will be added via the `Set()` function return nil } From 702c7cdf7a37f3a87fdd889e1adaee7c34704e02 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 29 Apr 2022 16:39:14 -0700 Subject: [PATCH 056/114] if running test iin github actions, use influxdb service for testing. --- .github/workflows/build.yaml | 3 +- webapp/backend/pkg/web/server_test.go | 69 ++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 064b177..916cb67 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -11,7 +11,7 @@ jobs: # Service containers to run with `build` (Required for end-to-end testing) services: influxdb: - image: influxdb:2.0 + image: influxdb:2.2 env: DOCKER_INFLUXDB_INIT_MODE: setup DOCKER_INFLUXDB_INIT_USERNAME: admin @@ -24,7 +24,6 @@ jobs: env: PROJECT_PATH: /go/src/github.com/analogj/scrutiny CGO_ENABLED: 1 - SCRUTINY_WEB_INFLUXDB_HOST: influxdb steps: - name: Git run: | diff --git a/webapp/backend/pkg/web/server_test.go b/webapp/backend/pkg/web/server_test.go index 0a247e7..b7816d8 100644 --- a/webapp/backend/pkg/web/server_test.go +++ b/webapp/backend/pkg/web/server_test.go @@ -70,13 +70,19 @@ func TestHealthRoute(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").Return(path.Join(parentPath, "scrutiny_test.db")).AnyTimes() fakeConfig.EXPECT().GetString("web.src.frontend.path").Return(parentPath).AnyTimes() - fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() + if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions { + // when running test suite in github actions, we run an influxdb service as a sidecar. + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes() + } else { + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + } ae := web.AppEngine{ Config: fakeConfig, @@ -103,13 +109,18 @@ func TestRegisterDevicesRoute(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").Return(path.Join(parentPath, "scrutiny_test.db")).AnyTimes() fakeConfig.EXPECT().GetString("web.src.frontend.path").Return(parentPath).AnyTimes() - fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() + if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions { + // when running test suite in github actions, we run an influxdb service as a sidecar. + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes() + } else { + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + } ae := web.AppEngine{ Config: fakeConfig, @@ -136,13 +147,18 @@ func TestUploadDeviceMetricsRoute(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) - fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() + if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions { + // when running test suite in github actions, we run an influxdb service as a sidecar. + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes() + } else { + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + } ae := web.AppEngine{ Config: fakeConfig, @@ -178,13 +194,18 @@ func TestPopulateMultiple(t *testing.T) { fakeConfig.EXPECT().GetStringSlice("notify.urls").Return([]string{}).AnyTimes() fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) - fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() + if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions { + // when running test suite in github actions, we run an influxdb service as a sidecar. + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes() + } else { + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + } ae := web.AppEngine{ Config: fakeConfig, @@ -267,7 +288,6 @@ func TestSendTestNotificationRoute_WebhookFailure(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) - fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() @@ -275,6 +295,13 @@ func TestSendTestNotificationRoute_WebhookFailure(t *testing.T) { fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"https://unroutable.domain.example.asdfghj"}) + if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions { + // when running test suite in github actions, we run an influxdb service as a sidecar. + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes() + } else { + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + } + ae := web.AppEngine{ Config: fakeConfig, } @@ -298,7 +325,6 @@ func TestSendTestNotificationRoute_ScriptFailure(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) - fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() @@ -306,6 +332,13 @@ func TestSendTestNotificationRoute_ScriptFailure(t *testing.T) { fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"script:///missing/path/on/disk"}) + if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions { + // when running test suite in github actions, we run an influxdb service as a sidecar. + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes() + } else { + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + } + ae := web.AppEngine{ Config: fakeConfig, } @@ -329,15 +362,20 @@ func TestSendTestNotificationRoute_ScriptSuccess(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) - fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() - fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"script:///usr/bin/env"}) + if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions { + // when running test suite in github actions, we run an influxdb service as a sidecar. + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes() + } else { + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + } + ae := web.AppEngine{ Config: fakeConfig, } @@ -361,15 +399,19 @@ func TestSendTestNotificationRoute_ShoutrrrFailure(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) - fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.org").Return("scrutiny").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() - fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{"discord://invalidtoken@channel"}) + if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions { + // when running test suite in github actions, we run an influxdb service as a sidecar. + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes() + } else { + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + } ae := web.AppEngine{ Config: fakeConfig, } @@ -393,7 +435,6 @@ func TestGetDevicesSummaryRoute_Nvme(t *testing.T) { fakeConfig := mock_config.NewMockInterface(mockCtrl) fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(path.Join(parentPath, "scrutiny_test.db")) fakeConfig.EXPECT().GetString("web.src.frontend.path").AnyTimes().Return(parentPath) - fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.port").Return("8086").AnyTimes() fakeConfig.EXPECT().IsSet("web.influxdb.token").Return(true).AnyTimes() fakeConfig.EXPECT().GetString("web.influxdb.token").Return("my-super-secret-auth-token").AnyTimes() @@ -401,6 +442,12 @@ func TestGetDevicesSummaryRoute_Nvme(t *testing.T) { fakeConfig.EXPECT().GetString("web.influxdb.bucket").Return("metrics").AnyTimes() fakeConfig.EXPECT().GetBool("web.influxdb.retention_policy").Return(false).AnyTimes() fakeConfig.EXPECT().GetStringSlice("notify.urls").AnyTimes().Return([]string{}) + if _, isGithubActions := os.LookupEnv("GITHUB_ACTIONS"); isGithubActions { + // when running test suite in github actions, we run an influxdb service as a sidecar. + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("influxdb").AnyTimes() + } else { + fakeConfig.EXPECT().GetString("web.influxdb.host").Return("localhost").AnyTimes() + } ae := web.AppEngine{ Config: fakeConfig, From 8462d21e1404b2cfb948e981b07bb299c4ad7137 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 29 Apr 2022 22:16:56 -0700 Subject: [PATCH 057/114] waiting for influxdb before starting scrutiny app. --- rootfs/etc/services.d/scrutiny/run | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rootfs/etc/services.d/scrutiny/run b/rootfs/etc/services.d/scrutiny/run index 3b88505..38b3c9d 100644 --- a/rootfs/etc/services.d/scrutiny/run +++ b/rootfs/etc/services.d/scrutiny/run @@ -1,5 +1,7 @@ #!/usr/bin/with-contenv bash -echo "starting scrutiny" +echo "waiting for influxdb" +until $(curl --output /dev/null --silent --head --fail http://localhost:8086/health); do echo "not ready"; done +echo "starting scrutiny" scrutiny start From 9a5c6674379fe6e310892b3d95c55c1693a656b7 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 29 Apr 2022 22:48:10 -0700 Subject: [PATCH 058/114] tweak the wait script. --- docker/README.md | 1 + rootfs/etc/services.d/collector-once/run | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 docker/README.md diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..0e11273 --- /dev/null +++ b/docker/README.md @@ -0,0 +1 @@ +`rootfs` is only used by Dockerfile and Dockerfile.collector diff --git a/rootfs/etc/services.d/collector-once/run b/rootfs/etc/services.d/collector-once/run index 46369a1..2fc2dc2 100644 --- a/rootfs/etc/services.d/collector-once/run +++ b/rootfs/etc/services.d/collector-once/run @@ -7,8 +7,7 @@ s6-svwait -u /var/run/s6/services/scrutiny s6-svc -O /var/run/s6/services/collector-once # wait until scrutiny is "Ready" -while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' http://localhost:8080/api/health)" != "200" ]]; do sleep 5; done - +until $(curl --output /dev/null --silent --head --fail http://localhost:8080/api/health); do echo "not ready" && sleep 5; done echo "starting scrutiny collector" /scrutiny/bin/scrutiny-collector-metrics run From 88a99a1c90217e2e20609404f56a31be297cbaff Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 29 Apr 2022 23:08:39 -0700 Subject: [PATCH 059/114] information about downsampling. --- CONTRIBUTING.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index da29a48..d1bac7e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -131,3 +131,16 @@ Finally, you can copy the files from the scrutiny container to your host using t docker cp scrutiny:/tmp/collector.log collector.log docker cp scrutiny:/tmp/web.log web.log ``` + +# InfluxDB - Downsampling + +Scrutiny will automatically configure downsampling scripts for ensuring the database size will not grow unbounded. + +| Bucket Name | Description | Retention Period | Downsampling Frequency | Max Number of Datapoints (per Disk) | +| --- | --- | --- | --- | --- | +| `scrutiny` | Main bucket, where all data is written | 15 days | `0 1 * * 0` | **7**+7+1 | +| `scrutiny_weekly` | Weekly data, downsampled from `scrutiny` | 9 weeks | `30 1 1 * *` | **4**+4+1 | +| `scrutiny_monthly` | Monthly data, downsampled from `_weekly` | 25 months | `0 2 1 1 *` | **12**+12+1 | +| `scrutiny_yearly` | Yearly data, downsampled from `_monthly` | forever | `never` | ∞ | + + From 9ebf252d4fb7b9e2eb9c3c08af3517945aabe852 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 11:47:17 -0700 Subject: [PATCH 060/114] information about downsampling. --- CONTRIBUTING.md | 13 ------------- docs/DOWNSAMPLING.md | 5 +++-- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d1bac7e..da29a48 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -131,16 +131,3 @@ Finally, you can copy the files from the scrutiny container to your host using t docker cp scrutiny:/tmp/collector.log collector.log docker cp scrutiny:/tmp/web.log web.log ``` - -# InfluxDB - Downsampling - -Scrutiny will automatically configure downsampling scripts for ensuring the database size will not grow unbounded. - -| Bucket Name | Description | Retention Period | Downsampling Frequency | Max Number of Datapoints (per Disk) | -| --- | --- | --- | --- | --- | -| `scrutiny` | Main bucket, where all data is written | 15 days | `0 1 * * 0` | **7**+7+1 | -| `scrutiny_weekly` | Weekly data, downsampled from `scrutiny` | 9 weeks | `30 1 1 * *` | **4**+4+1 | -| `scrutiny_monthly` | Monthly data, downsampled from `_weekly` | 25 months | `0 2 1 1 *` | **12**+12+1 | -| `scrutiny_yearly` | Yearly data, downsampled from `_monthly` | forever | `never` | ∞ | - - diff --git a/docs/DOWNSAMPLING.md b/docs/DOWNSAMPLING.md index 25a202a..70eeea0 100644 --- a/docs/DOWNSAMPLING.md +++ b/docs/DOWNSAMPLING.md @@ -17,7 +17,7 @@ ensuring historical data is present for comparisons. | Bucket Name | Retention Period | Downsampling Range | Downsampling Aggregation Window | Downsampling Cron | Comments | | --- | --- | --- | --- | --- | --- | -| `metrics` | 15 days | `-2w -1w` | `1w` | weekly on Sunday at 1:00am | +| `metrics` | 15 days | `-2w -1w` | `1w` | main bucket, weekly on Sunday at 1:00am | | `metrics_weekly` | 9 weeks | `-2mo -1mo` | `1mo` | monthly on first day of the month at 1:30am | `metrics_monthly` | 25 months | `-2y -1y` | `1y` | yearly on the first day of the year at 2:00am | `metrics_yearly` | forever | - | - | - | | @@ -39,4 +39,5 @@ After 5 years, here's how may data points should exist in each bucket for one di | `metrics` | - | - | | `metrics_weekly` | - | | `metrics_monthly` | - | -| `metrics_yearly` | - | +| `metrics_yearly` | - | + From 5fb5b9afbe27b3b05c670a98de26bf7844495e97 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 15:56:48 -0700 Subject: [PATCH 061/114] if we're completing the InfluxDB setup via automation, attempt to store the token in the config file automatically. --- webapp/backend/pkg/config/interface.go | 1 + webapp/backend/pkg/database/scrutiny_repository.go | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/webapp/backend/pkg/config/interface.go b/webapp/backend/pkg/config/interface.go index fabe8af..8f0b773 100644 --- a/webapp/backend/pkg/config/interface.go +++ b/webapp/backend/pkg/config/interface.go @@ -9,6 +9,7 @@ import ( type Interface interface { Init() error ReadConfig(configFilePath string) error + WriteConfig() error Set(key string, value interface{}) SetDefault(key string, value interface{}) diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index 0102771..f442a20 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -99,7 +99,9 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field } appConfig.Set("web.influxdb.token", *onboardingResponse.Auth.Token) - //todo: determine if we should write the config file out here. + // we should write the config file out here. Ignore failures. + _ = appConfig.WriteConfig() + } // Use blocking write client for writes to desired bucket From 5a1e390acdf4a09540730d7c97821f0be8d24aae Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 15:57:09 -0700 Subject: [PATCH 062/114] started writing a TROUBLESHOOTING guide for the device collector. --- docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md | 117 +++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md diff --git a/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md b/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md new file mode 100644 index 0000000..f0386bd --- /dev/null +++ b/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md @@ -0,0 +1,117 @@ +# Scrutiny <-> SmartMonTools + +Scrutiny uses `smartctl --scan` to detect devices/drives. If your devices are not being detected by Scrutiny, or some +data is missing, this is probably due to a `smartctl` issue. +The following page will document commonly asked questions and troubleshooting steps for the Scrutiny S.M.A.R.T. data collector. + +## WWN vs Device name +As discussed in [`#117`](https://github.com/AnalogJ/scrutiny/issues/117), `/dev/sd*` device paths are ephemeral. + +> Device paths in Linux aren't guaranteed to be consistent across restarts. Device names consist of major numbers (letters) and minor numbers. When the Linux storage device driver detects a new device, the driver assigns major and minor numbers from the available range to the device. When a device is removed, the device numbers are freed for reuse. +> +> The problem occurs because device scanning in Linux is scheduled by the SCSI subsystem to happen asynchronously. As a result, a device path name can vary across restarts. +> +> https://docs.microsoft.com/en-us/troubleshoot/azure/virtual-machines/troubleshoot-device-names-problems + +While the Docker Scrutiny collector does require devices to attached to the docker container by device name (using `--device=/dev/sd..`), internally +Scrutiny stores and references the devices by their `WWN` which is globally unique, and never changes. + +As such, passing devices to the Scrutiny collector container using `/dev/disk/by-id/`, `/dev/disk/by-label/`, `/dev/disk/by-path/` and `/dev/disk/by-uuid/` +paths are unnecessary, unless you'd like to ensure the docker run command never needs to change. + + +## Device Detection By Smartctl + +The first thing you'll want to do is run `smartctl` locally (not in Docker) and make sure the output shows all your drives as expected. +See the `Drive Types` section below for what this output should look like for `NVMe`/`ATA`/`RAID` drives. + +```bash +smartctl --scan + +/dev/sda -d scsi # /dev/sda, SCSI device +/dev/sdb -d scsi # /dev/sdb, SCSI device +/dev/sdc -d scsi # /dev/sdc, SCSI device +/dev/sdd -d scsi # /dev/sdd, SCSI device +``` + +Once you've verified that `smartctl` correctly detects your drives, make sure scrutiny is correctly detecting them as well. +> NOTE: make sure you specify all the devices you'd like scrutiny to process using `--device=` flags. + +```bash +docker run -it --rm \ + -v /run/udev:/run/udev:ro \ + --cap-add SYS_RAWIO \ + --device=/dev/sda \ + --device=/dev/sdb \ + analogj/scrutiny:collector smartctl --scan +``` + +If the output is the same, your devices will be processed by Scrutiny. + +# Collector Config File +In some cases `--scan` does not correctly detect the device type, returning [incomplete SMART data](https://github.com/AnalogJ/scrutiny/issues/45). +Scrutiny will supports overriding the detected device type via the config file. + +# RAID Controllers (Megaraid/3ware/HBA/Adaptec/HPE/etc) +Smartctl has support for a large number of [RAID controllers](https://www.smartmontools.org/wiki/Supported_RAID-Controllers), however this +support is not automatic, and may require some additional device type hinting. You can provide this information to the Scrutiny collector +using a collector config file. See [example.collector.yaml](/example.collector.yaml) + +```yaml +# /scrutiny/config/collector.yaml +devices: + # Dell PERC/Broadcom Megaraid example: https://github.com/AnalogJ/scrutiny/issues/30 + - device: /dev/bus/0 + type: + - megaraid,14 + - megaraid,15 + - megaraid,18 + - megaraid,19 + - megaraid,20 + - megaraid,21 + + - device: /dev/twa0 + type: + - 3ware,0 + - 3ware,1 + - 3ware,2 + - 3ware,3 + - 3ware,4 + - 3ware,5 + + # Adapec RAID: https://github.com/AnalogJ/scrutiny/issues/189 + - device: /dev/sdb + type: + - aacraid,0,0,0 + - aacraid,0,0,1 + + # HPE Smart Array example: https://github.com/AnalogJ/scrutiny/issues/213 + - device: /dev/sda + type: + - 'cciss,0' + - 'cciss,1' +``` + +# NVMe Drives + +# ATA + +# Standby/Sleeping Disks + + + +## Hub & Spoke model, with multiple Hosts. + +When deploying Scrutiny in a hub & spoke model, it can be difficult to determine exactly which node a set of devices are associated with. +Thankfully the collector has a special `--host-id` flag (or `COLLECTOR_HOST_ID` env variable) that can be used to associate devices with a friendly host name. + +See the [docs/INSTALL_HUB_SPOKE.md](/docs/INSTALL_HUB_SPOKE.md) guide for more information. + + +- All RAID controllers supported by `smartctl` are automatically supported by Scrutiny. + - While some RAID controllers support passing through the underlying SMART data to `smartctl` others do not. + - In some cases `--scan` does not correctly detect the device type, returning [incomplete SMART data](https://github.com/AnalogJ/scrutiny/issues/45). + Scrutiny will eventually support overriding detected device type via the config file. +- If you use docker, you **must** pass though the RAID virtual disk to the container using `--device` (see below) + - This device may be in `/dev/*` or `/dev/bus/*`. + - If you're unsure, run `smartctl --scan` on your host, and pass all listed devices to the container. From 9ee267480443b2cacde1b77ef2800f0b9437086e Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 15:59:45 -0700 Subject: [PATCH 063/114] started writing a TROUBLESHOOTING guide for the device collector. --- docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md b/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md index f0386bd..67c10e1 100644 --- a/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md +++ b/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md @@ -57,6 +57,12 @@ Smartctl has support for a large number of [RAID controllers](https://www.smartm support is not automatic, and may require some additional device type hinting. You can provide this information to the Scrutiny collector using a collector config file. See [example.collector.yaml](/example.collector.yaml) +> NOTE: If you use docker, you **must** pass though the RAID virtual disk to the container using `--device` (see below) +> +> This device may be in `/dev/*` or `/dev/bus/*`. +> +> If you're unsure, run `smartctl --scan` on your host, and pass all listed devices to the container. + ```yaml # /scrutiny/config/collector.yaml devices: @@ -107,11 +113,3 @@ Thankfully the collector has a special `--host-id` flag (or `COLLECTOR_HOST_ID` See the [docs/INSTALL_HUB_SPOKE.md](/docs/INSTALL_HUB_SPOKE.md) guide for more information. - -- All RAID controllers supported by `smartctl` are automatically supported by Scrutiny. - - While some RAID controllers support passing through the underlying SMART data to `smartctl` others do not. - - In some cases `--scan` does not correctly detect the device type, returning [incomplete SMART data](https://github.com/AnalogJ/scrutiny/issues/45). - Scrutiny will eventually support overriding detected device type via the config file. -- If you use docker, you **must** pass though the RAID virtual disk to the container using `--device` (see below) - - This device may be in `/dev/*` or `/dev/bus/*`. - - If you're unsure, run `smartctl --scan` on your host, and pass all listed devices to the container. From e243d55153c489231fa9967308651a56c3289665 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 16:09:16 -0700 Subject: [PATCH 064/114] Document NVMe block device vs device controller binding. Fixes #209. --- docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md b/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md index 67c10e1..a315593 100644 --- a/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md +++ b/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md @@ -52,7 +52,7 @@ If the output is the same, your devices will be processed by Scrutiny. In some cases `--scan` does not correctly detect the device type, returning [incomplete SMART data](https://github.com/AnalogJ/scrutiny/issues/45). Scrutiny will supports overriding the detected device type via the config file. -# RAID Controllers (Megaraid/3ware/HBA/Adaptec/HPE/etc) +## RAID Controllers (Megaraid/3ware/HBA/Adaptec/HPE/etc) Smartctl has support for a large number of [RAID controllers](https://www.smartmontools.org/wiki/Supported_RAID-Controllers), however this support is not automatic, and may require some additional device type hinting. You can provide this information to the Scrutiny collector using a collector config file. See [example.collector.yaml](/example.collector.yaml) @@ -99,6 +99,17 @@ devices: ``` # NVMe Drives +As mentioned in the [README.md](/README.md), NVMe devices require both `--cap-add SYS_RAWIO` and `--cap-add SYS_ADMIN` +to allow smartctl permission to query your NVMe device SMART data [#26](https://github.com/AnalogJ/scrutiny/issues/26) + +When attaching NVMe devices using `--device=/dev/nvme..`, make sure to provide the device controller (`/dev/nvme0`) +instead of the block device (`/dev/nvme0n1`). See [#209](https://github.com/AnalogJ/scrutiny/issues/209). + +> The character device /dev/nvme0 is the NVME device controller, and block devices like /dev/nvme0n1 are the NVME storage namespaces: the devices you use for actual storage, which will behave essentially as disks. +> +> In enterprise-grade hardware, there might be support for several namespaces, thin provisioning within namespaces and other features. For now, you could think namespaces as sort of meta-partitions with extra features for enterprise use. + + # ATA From 5a4bcda1ec0fac49859e3cbaca2fe0efc650d7d4 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 21:13:18 -0700 Subject: [PATCH 065/114] adding more docs. --- docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md b/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md index a315593..225a94c 100644 --- a/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md +++ b/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md @@ -48,11 +48,11 @@ docker run -it --rm \ If the output is the same, your devices will be processed by Scrutiny. -# Collector Config File +### Collector Config File In some cases `--scan` does not correctly detect the device type, returning [incomplete SMART data](https://github.com/AnalogJ/scrutiny/issues/45). Scrutiny will supports overriding the detected device type via the config file. -## RAID Controllers (Megaraid/3ware/HBA/Adaptec/HPE/etc) +### RAID Controllers (Megaraid/3ware/HBA/Adaptec/HPE/etc) Smartctl has support for a large number of [RAID controllers](https://www.smartmontools.org/wiki/Supported_RAID-Controllers), however this support is not automatic, and may require some additional device type hinting. You can provide this information to the Scrutiny collector using a collector config file. See [example.collector.yaml](/example.collector.yaml) @@ -98,7 +98,7 @@ devices: - 'cciss,1' ``` -# NVMe Drives +### NVMe Drives As mentioned in the [README.md](/README.md), NVMe devices require both `--cap-add SYS_RAWIO` and `--cap-add SYS_ADMIN` to allow smartctl permission to query your NVMe device SMART data [#26](https://github.com/AnalogJ/scrutiny/issues/26) @@ -109,12 +109,13 @@ instead of the block device (`/dev/nvme0n1`). See [#209](https://github.com/Anal > > In enterprise-grade hardware, there might be support for several namespaces, thin provisioning within namespaces and other features. For now, you could think namespaces as sort of meta-partitions with extra features for enterprise use. +### ATA +### Standby/Sleeping Disks +- https://github.com/AnalogJ/scrutiny/issues/221 +- https://github.com/AnalogJ/scrutiny/issues/157 -# ATA - -# Standby/Sleeping Disks - +### Volume Mount All Devices (`/dev`) - Privileged ## Hub & Spoke model, with multiple Hosts. From d42faf30b034a945073744aa1a2374355c818645 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 21:17:57 -0700 Subject: [PATCH 066/114] fix WriteConfig interface. --- webapp/backend/pkg/config/mock/mock_config.go | 181 ++++++++++-------- 1 file changed, 98 insertions(+), 83 deletions(-) diff --git a/webapp/backend/pkg/config/mock/mock_config.go b/webapp/backend/pkg/config/mock/mock_config.go index c9ee399..8e54f6f 100644 --- a/webapp/backend/pkg/config/mock/mock_config.go +++ b/webapp/backend/pkg/config/mock/mock_config.go @@ -5,185 +5,186 @@ package mock_config import ( + reflect "reflect" + gomock "github.com/golang/mock/gomock" viper "github.com/spf13/viper" - reflect "reflect" ) -// MockInterface is a mock of Interface interface +// MockInterface is a mock of Interface interface. type MockInterface struct { ctrl *gomock.Controller recorder *MockInterfaceMockRecorder } -// MockInterfaceMockRecorder is the mock recorder for MockInterface +// MockInterfaceMockRecorder is the mock recorder for MockInterface. type MockInterfaceMockRecorder struct { mock *MockInterface } -// NewMockInterface creates a new mock instance +// NewMockInterface creates a new mock instance. func NewMockInterface(ctrl *gomock.Controller) *MockInterface { mock := &MockInterface{ctrl: ctrl} mock.recorder = &MockInterfaceMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder { return m.recorder } -// Init mocks base method -func (m *MockInterface) Init() error { +// AllSettings mocks base method. +func (m *MockInterface) AllSettings() map[string]interface{} { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Init") - ret0, _ := ret[0].(error) + ret := m.ctrl.Call(m, "AllSettings") + ret0, _ := ret[0].(map[string]interface{}) return ret0 } -// Init indicates an expected call of Init -func (mr *MockInterfaceMockRecorder) Init() *gomock.Call { +// AllSettings indicates an expected call of AllSettings. +func (mr *MockInterfaceMockRecorder) AllSettings() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockInterface)(nil).Init)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllSettings", reflect.TypeOf((*MockInterface)(nil).AllSettings)) } -// ReadConfig mocks base method -func (m *MockInterface) ReadConfig(configFilePath string) error { +// Get mocks base method. +func (m *MockInterface) Get(key string) interface{} { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ReadConfig", configFilePath) - ret0, _ := ret[0].(error) + ret := m.ctrl.Call(m, "Get", key) + ret0, _ := ret[0].(interface{}) return ret0 } -// ReadConfig indicates an expected call of ReadConfig -func (mr *MockInterfaceMockRecorder) ReadConfig(configFilePath interface{}) *gomock.Call { +// Get indicates an expected call of Get. +func (mr *MockInterfaceMockRecorder) Get(key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadConfig", reflect.TypeOf((*MockInterface)(nil).ReadConfig), configFilePath) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockInterface)(nil).Get), key) } -// Set mocks base method -func (m *MockInterface) Set(key string, value interface{}) { +// GetBool mocks base method. +func (m *MockInterface) GetBool(key string) bool { m.ctrl.T.Helper() - m.ctrl.Call(m, "Set", key, value) + ret := m.ctrl.Call(m, "GetBool", key) + ret0, _ := ret[0].(bool) + return ret0 } -// Set indicates an expected call of Set -func (mr *MockInterfaceMockRecorder) Set(key, value interface{}) *gomock.Call { +// GetBool indicates an expected call of GetBool. +func (mr *MockInterfaceMockRecorder) GetBool(key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockInterface)(nil).Set), key, value) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBool", reflect.TypeOf((*MockInterface)(nil).GetBool), key) } -// SetDefault mocks base method -func (m *MockInterface) SetDefault(key string, value interface{}) { +// GetInt mocks base method. +func (m *MockInterface) GetInt(key string) int { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetDefault", key, value) + ret := m.ctrl.Call(m, "GetInt", key) + ret0, _ := ret[0].(int) + return ret0 } -// SetDefault indicates an expected call of SetDefault -func (mr *MockInterfaceMockRecorder) SetDefault(key, value interface{}) *gomock.Call { +// GetInt indicates an expected call of GetInt. +func (mr *MockInterfaceMockRecorder) GetInt(key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDefault", reflect.TypeOf((*MockInterface)(nil).SetDefault), key, value) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInt", reflect.TypeOf((*MockInterface)(nil).GetInt), key) } -// AllSettings mocks base method -func (m *MockInterface) AllSettings() map[string]interface{} { +// GetString mocks base method. +func (m *MockInterface) GetString(key string) string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AllSettings") - ret0, _ := ret[0].(map[string]interface{}) + ret := m.ctrl.Call(m, "GetString", key) + ret0, _ := ret[0].(string) return ret0 } -// AllSettings indicates an expected call of AllSettings -func (mr *MockInterfaceMockRecorder) AllSettings() *gomock.Call { +// GetString indicates an expected call of GetString. +func (mr *MockInterfaceMockRecorder) GetString(key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllSettings", reflect.TypeOf((*MockInterface)(nil).AllSettings)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetString", reflect.TypeOf((*MockInterface)(nil).GetString), key) } -// IsSet mocks base method -func (m *MockInterface) IsSet(key string) bool { +// GetStringSlice mocks base method. +func (m *MockInterface) GetStringSlice(key string) []string { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsSet", key) - ret0, _ := ret[0].(bool) + ret := m.ctrl.Call(m, "GetStringSlice", key) + ret0, _ := ret[0].([]string) return ret0 } -// IsSet indicates an expected call of IsSet -func (mr *MockInterfaceMockRecorder) IsSet(key interface{}) *gomock.Call { +// GetStringSlice indicates an expected call of GetStringSlice. +func (mr *MockInterfaceMockRecorder) GetStringSlice(key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSet", reflect.TypeOf((*MockInterface)(nil).IsSet), key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStringSlice", reflect.TypeOf((*MockInterface)(nil).GetStringSlice), key) } -// Get mocks base method -func (m *MockInterface) Get(key string) interface{} { +// Init mocks base method. +func (m *MockInterface) Init() error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Get", key) - ret0, _ := ret[0].(interface{}) + ret := m.ctrl.Call(m, "Init") + ret0, _ := ret[0].(error) return ret0 } -// Get indicates an expected call of Get -func (mr *MockInterfaceMockRecorder) Get(key interface{}) *gomock.Call { +// Init indicates an expected call of Init. +func (mr *MockInterfaceMockRecorder) Init() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockInterface)(nil).Get), key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockInterface)(nil).Init)) } -// GetBool mocks base method -func (m *MockInterface) GetBool(key string) bool { +// IsSet mocks base method. +func (m *MockInterface) IsSet(key string) bool { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBool", key) + ret := m.ctrl.Call(m, "IsSet", key) ret0, _ := ret[0].(bool) return ret0 } -// GetBool indicates an expected call of GetBool -func (mr *MockInterfaceMockRecorder) GetBool(key interface{}) *gomock.Call { +// IsSet indicates an expected call of IsSet. +func (mr *MockInterfaceMockRecorder) IsSet(key interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBool", reflect.TypeOf((*MockInterface)(nil).GetBool), key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSet", reflect.TypeOf((*MockInterface)(nil).IsSet), key) } -// GetInt mocks base method -func (m *MockInterface) GetInt(key string) int { +// ReadConfig mocks base method. +func (m *MockInterface) ReadConfig(configFilePath string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetInt", key) - ret0, _ := ret[0].(int) + ret := m.ctrl.Call(m, "ReadConfig", configFilePath) + ret0, _ := ret[0].(error) return ret0 } -// GetInt indicates an expected call of GetInt -func (mr *MockInterfaceMockRecorder) GetInt(key interface{}) *gomock.Call { +// ReadConfig indicates an expected call of ReadConfig. +func (mr *MockInterfaceMockRecorder) ReadConfig(configFilePath interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInt", reflect.TypeOf((*MockInterface)(nil).GetInt), key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadConfig", reflect.TypeOf((*MockInterface)(nil).ReadConfig), configFilePath) } -// GetString mocks base method -func (m *MockInterface) GetString(key string) string { +// Set mocks base method. +func (m *MockInterface) Set(key string, value interface{}) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetString", key) - ret0, _ := ret[0].(string) - return ret0 + m.ctrl.Call(m, "Set", key, value) } -// GetString indicates an expected call of GetString -func (mr *MockInterfaceMockRecorder) GetString(key interface{}) *gomock.Call { +// Set indicates an expected call of Set. +func (mr *MockInterfaceMockRecorder) Set(key, value interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetString", reflect.TypeOf((*MockInterface)(nil).GetString), key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockInterface)(nil).Set), key, value) } -// GetStringSlice mocks base method -func (m *MockInterface) GetStringSlice(key string) []string { +// SetDefault mocks base method. +func (m *MockInterface) SetDefault(key string, value interface{}) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetStringSlice", key) - ret0, _ := ret[0].([]string) - return ret0 + m.ctrl.Call(m, "SetDefault", key, value) } -// GetStringSlice indicates an expected call of GetStringSlice -func (mr *MockInterfaceMockRecorder) GetStringSlice(key interface{}) *gomock.Call { +// SetDefault indicates an expected call of SetDefault. +func (mr *MockInterfaceMockRecorder) SetDefault(key, value interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStringSlice", reflect.TypeOf((*MockInterface)(nil).GetStringSlice), key) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDefault", reflect.TypeOf((*MockInterface)(nil).SetDefault), key, value) } -// UnmarshalKey mocks base method +// UnmarshalKey mocks base method. func (m *MockInterface) UnmarshalKey(key string, rawVal interface{}, decoderOpts ...viper.DecoderConfigOption) error { m.ctrl.T.Helper() varargs := []interface{}{key, rawVal} @@ -195,9 +196,23 @@ func (m *MockInterface) UnmarshalKey(key string, rawVal interface{}, decoderOpts return ret0 } -// UnmarshalKey indicates an expected call of UnmarshalKey +// UnmarshalKey indicates an expected call of UnmarshalKey. func (mr *MockInterfaceMockRecorder) UnmarshalKey(key, rawVal interface{}, decoderOpts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{key, rawVal}, decoderOpts...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnmarshalKey", reflect.TypeOf((*MockInterface)(nil).UnmarshalKey), varargs...) } + +// WriteConfig mocks base method. +func (m *MockInterface) WriteConfig() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WriteConfig") + ret0, _ := ret[0].(error) + return ret0 +} + +// WriteConfig indicates an expected call of WriteConfig. +func (mr *MockInterfaceMockRecorder) WriteConfig() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteConfig", reflect.TypeOf((*MockInterface)(nil).WriteConfig)) +} From 62e5a71eb07cf69dc195a4f64bea528ab4405636 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 21:27:45 -0700 Subject: [PATCH 067/114] build darwin/amd64 and darwin/arm64 binaries. --- .github/workflows/build.yaml | 4 ++++ .github/workflows/release.yaml | 41 ++++++++++++++++++++++++++++++++++ Makefile | 2 ++ 3 files changed, 47 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 53b607f..94399cd 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -61,6 +61,10 @@ jobs: /build/scrutiny-collector-metrics-linux-arm-6 /build/scrutiny-web-linux-arm-7 /build/scrutiny-collector-metrics-linux-arm-7 + /build/scrutiny-web-darwin-arm64 + /build/scrutiny-collector-metrics-darwin-arm64 + /build/scrutiny-web-darwin-amd64 + /build/scrutiny-collector-metrics-darwin-amd64 /build/scrutiny-web-windows-4.0-amd64.exe /build/scrutiny-collector-metrics-windows-4.0-amd64.exe # /build/scrutiny-web-freebsd-amd64 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 352da1d..0b309ed 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -212,3 +212,44 @@ jobs: asset_path: /build/scrutiny-collector-metrics-windows-4.0-amd64.exe asset_name: scrutiny-collector-metrics-windows-4.0-amd64.exe asset_content_type: application/octet-stream + + - name: Release Asset - Web - darwin-arm64 + id: upload-release-asset13 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-web-darwin-arm64 + asset_name: scrutiny-web-darwin-arm64 + asset_content_type: application/octet-stream + - name: Release Asset - Collector - darwin-arm64 + id: upload-release-asset14 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-collector-metrics-darwin-arm64 + asset_name: scrutiny-collector-metrics-darwin-arm64 + asset_content_type: application/octet-stream + - name: Release Asset - Web - darwin-amd64 + id: upload-release-asset15 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-web-darwin-amd64 + asset_name: scrutiny-web-darwin-amd64 + asset_content_type: application/octet-stream + - name: Release Asset - Collector - darwin-amd64 + id: upload-release-asset16 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: /build/scrutiny-collector-metrics-darwin-amd64 + asset_name: scrutiny-collector-metrics-darwin-amd64 + asset_content_type: application/octet-stream \ No newline at end of file diff --git a/Makefile b/Makefile index c22f82e..5306a77 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,8 @@ BINARY=\ linux/arm-6 \ linux/arm-7 \ linux/arm64 \ + darwin/arm64 \ + darwin/amd64 \ .PHONY: all $(BINARY) From cfe77c9a36b34fea700863c3ff8f98df3be589d8 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 21:29:45 -0700 Subject: [PATCH 068/114] install tzdata package everywhere. fixes #78 fixes --- docker/Dockerfile | 2 +- docker/Dockerfile.collector | 2 +- docker/Dockerfile.web | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index d1bda0c..2e37fba 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -32,7 +32,7 @@ WORKDIR /scrutiny ENV PATH="/scrutiny/bin:${PATH}" ENV INFLUXD_CONFIG_PATH=/scrutiny/influxdb -RUN apt-get update && apt-get install -y cron smartmontools=7.0-0ubuntu1~ubuntu18.04.1 ca-certificates curl && update-ca-certificates +RUN apt-get update && apt-get install -y cron smartmontools=7.0-0ubuntu1~ubuntu18.04.1 ca-certificates curl tzdata && update-ca-certificates ADD https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s6-overlay-amd64.tar.gz /tmp/ RUN tar xzf /tmp/s6-overlay-amd64.tar.gz -C / diff --git a/docker/Dockerfile.collector b/docker/Dockerfile.collector index 32361ba..76bf838 100644 --- a/docker/Dockerfile.collector +++ b/docker/Dockerfile.collector @@ -14,7 +14,7 @@ FROM ubuntu:bionic as runtime WORKDIR /scrutiny ENV PATH="/scrutiny/bin:${PATH}" -RUN apt-get update && apt-get install -y cron smartmontools=7.0-0ubuntu1~ubuntu18.04.1 ca-certificates && update-ca-certificates +RUN apt-get update && apt-get install -y cron smartmontools=7.0-0ubuntu1~ubuntu18.04.1 ca-certificates tzdata && update-ca-certificates COPY /docker/entrypoint-collector.sh /entrypoint-collector.sh COPY /rootfs/etc/cron.d/scrutiny /etc/cron.d/scrutiny diff --git a/docker/Dockerfile.web b/docker/Dockerfile.web index c9174a7..e942b5f 100644 --- a/docker/Dockerfile.web +++ b/docker/Dockerfile.web @@ -29,7 +29,7 @@ EXPOSE 8080 WORKDIR /scrutiny ENV PATH="/scrutiny/bin:${PATH}" -RUN apt-get update && apt-get install -y ca-certificates curl && update-ca-certificates +RUN apt-get update && apt-get install -y ca-certificates curl tzdata && update-ca-certificates COPY --from=backendbuild /go/src/github.com/analogj/scrutiny/scrutiny /scrutiny/bin/ COPY --from=frontendbuild /scrutiny/dist /scrutiny/web From 8d052f0265c1112dde0575b0bf1b6105d5a4f580 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 21:33:40 -0700 Subject: [PATCH 069/114] update the bug report template --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 7fdb7fd..2c67489 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -18,6 +18,7 @@ If applicable, add screenshots to help explain your problem. **Log Files** If related to missing devices or SMART data, please run the `collector` in DEBUG mode, and attach the log file. +See [/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md](docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md) for other troubleshooting tips. ``` docker run -it --rm -p 8080:8080 \ @@ -37,5 +38,4 @@ docker exec scrutiny scrutiny-collector-metrics run # then use docker cp to copy the log files out of the container. docker cp scrutiny:/tmp/collector.log collector.log docker cp scrutiny:/tmp/web.log web.log - ``` From ccbb9225c4c34d2eca5aa76168ed84891d03dfbc Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 22:03:17 -0700 Subject: [PATCH 070/114] remove darwin builds. --- .github/workflows/build.yaml | 8 ++-- .github/workflows/release.yaml | 82 +++++++++++++++++----------------- Makefile | 3 -- 3 files changed, 45 insertions(+), 48 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 94399cd..c31c3b3 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -61,12 +61,12 @@ jobs: /build/scrutiny-collector-metrics-linux-arm-6 /build/scrutiny-web-linux-arm-7 /build/scrutiny-collector-metrics-linux-arm-7 - /build/scrutiny-web-darwin-arm64 - /build/scrutiny-collector-metrics-darwin-arm64 - /build/scrutiny-web-darwin-amd64 - /build/scrutiny-collector-metrics-darwin-amd64 /build/scrutiny-web-windows-4.0-amd64.exe /build/scrutiny-collector-metrics-windows-4.0-amd64.exe +# /build/scrutiny-web-darwin-arm64 +# /build/scrutiny-collector-metrics-darwin-arm64 +# /build/scrutiny-web-darwin-amd64 +# /build/scrutiny-collector-metrics-darwin-amd64 # /build/scrutiny-web-freebsd-amd64 # /build/scrutiny-collector-metrics-freebsd-amd64 - uses: codecov/codecov-action@v1 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0b309ed..7cc9ebb 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -212,44 +212,44 @@ jobs: asset_path: /build/scrutiny-collector-metrics-windows-4.0-amd64.exe asset_name: scrutiny-collector-metrics-windows-4.0-amd64.exe asset_content_type: application/octet-stream - - - name: Release Asset - Web - darwin-arm64 - id: upload-release-asset13 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-web-darwin-arm64 - asset_name: scrutiny-web-darwin-arm64 - asset_content_type: application/octet-stream - - name: Release Asset - Collector - darwin-arm64 - id: upload-release-asset14 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-collector-metrics-darwin-arm64 - asset_name: scrutiny-collector-metrics-darwin-arm64 - asset_content_type: application/octet-stream - - name: Release Asset - Web - darwin-amd64 - id: upload-release-asset15 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-web-darwin-amd64 - asset_name: scrutiny-web-darwin-amd64 - asset_content_type: application/octet-stream - - name: Release Asset - Collector - darwin-amd64 - id: upload-release-asset16 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-collector-metrics-darwin-amd64 - asset_name: scrutiny-collector-metrics-darwin-amd64 - asset_content_type: application/octet-stream \ No newline at end of file +# +# - name: Release Asset - Web - darwin-arm64 +# id: upload-release-asset13 +# uses: actions/upload-release-asset@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} +# with: +# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps +# asset_path: /build/scrutiny-web-darwin-arm64 +# asset_name: scrutiny-web-darwin-arm64 +# asset_content_type: application/octet-stream +# - name: Release Asset - Collector - darwin-arm64 +# id: upload-release-asset14 +# uses: actions/upload-release-asset@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} +# with: +# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps +# asset_path: /build/scrutiny-collector-metrics-darwin-arm64 +# asset_name: scrutiny-collector-metrics-darwin-arm64 +# asset_content_type: application/octet-stream +# - name: Release Asset - Web - darwin-amd64 +# id: upload-release-asset15 +# uses: actions/upload-release-asset@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} +# with: +# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps +# asset_path: /build/scrutiny-web-darwin-amd64 +# asset_name: scrutiny-web-darwin-amd64 +# asset_content_type: application/octet-stream +# - name: Release Asset - Collector - darwin-amd64 +# id: upload-release-asset16 +# uses: actions/upload-release-asset@v1 +# env: +# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} +# with: +# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps +# asset_path: /build/scrutiny-collector-metrics-darwin-amd64 +# asset_name: scrutiny-collector-metrics-darwin-amd64 +# asset_content_type: application/octet-stream \ No newline at end of file diff --git a/Makefile b/Makefile index 5306a77..360fa8f 100644 --- a/Makefile +++ b/Makefile @@ -8,9 +8,6 @@ BINARY=\ linux/arm-6 \ linux/arm-7 \ linux/arm64 \ - darwin/arm64 \ - darwin/amd64 \ - .PHONY: all $(BINARY) all: $(BINARY) windows/amd64 From 84f3327790161ff5f9c312cf4525b36f266ab6c6 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 22:19:16 -0700 Subject: [PATCH 071/114] adding codecov coverage support. --- .github/workflows/build.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index c31c3b3..7fcdba3 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -40,6 +40,12 @@ jobs: go mod vendor go test -race -coverprofile=coverage.txt -covermode=atomic -v -tags "static" $(go list ./... | grep -v /vendor/) + - uses: codecov/codecov-action@v2 + with: + files: ./coverage.txt + flags: unittests + fail_ci_if_error: true + verbose: true - name: Build Binaries run: | From 20411afb823baa26d4f26bddfa952c769cd87df1 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 22:20:06 -0700 Subject: [PATCH 072/114] adding name for coverage step. --- .github/workflows/build.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 7fcdba3..47e20e9 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -40,7 +40,8 @@ jobs: go mod vendor go test -race -coverprofile=coverage.txt -covermode=atomic -v -tags "static" $(go list ./... | grep -v /vendor/) - - uses: codecov/codecov-action@v2 + - name: Generate coverage report + uses: codecov/codecov-action@v2 with: files: ./coverage.txt flags: unittests From 035c94681f911d3fad7e8ba8aadf0e9ed69fc023 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 22:24:05 -0700 Subject: [PATCH 073/114] referencing Github container registry for all images. --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- CONTRIBUTING.md | 2 +- README.md | 6 +++--- docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 2c67489..dc01c62 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -30,7 +30,7 @@ docker run -it --rm -p 8080:8080 \ -e COLLECTOR_LOG_FILE=/tmp/collector.log \ -e SCRUTINY_LOG_FILE=/tmp/web.log \ --name scrutiny \ -analogj/scrutiny +ghcr.io/analogj/scrutiny:master-omnibus # in another terminal trigger the collector docker exec scrutiny scrutiny-collector-metrics run diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index da29a48..e4730dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ docker run -it --rm -p 8080:8080 \ --cap-add SYS_RAWIO \ --device=/dev/sda \ --device=/dev/sdb \ -analogj/scrutiny +ghcr.io/analogj/scrutiny:master-omnibus /scrutiny/bin/scrutiny-collector-metrics run ``` diff --git a/README.md b/README.md index 9a7a422..5172af6 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ docker run -it --rm -p 8080:8080 \ --device=/dev/sda \ --device=/dev/sdb \ --name scrutiny \ - analogj/scrutiny + ghcr.io/analogj/scrutiny:master-omnibus ``` - `/run/udev` is necessary to provide the Scrutiny collector with access to your device metadata @@ -96,7 +96,7 @@ In addition to the Omnibus image (available under the `latest` tag) there are 2 ```bash docker run -it --rm -p 8080:8080 \ --name scrutiny-web \ - analogj/scrutiny:web + ghcr.io/analogj/scrutiny:master-web docker run -it --rm \ -v /run/udev:/run/udev:ro \ @@ -105,7 +105,7 @@ docker run -it --rm \ --device=/dev/sdb \ -e SCRUTINY_API_ENDPOINT=http://SCRUTINY_WEB_IPADDRESS:8080 \ --name scrutiny-collector \ - analogj/scrutiny:collector + ghcr.io/analogj/scrutiny:master-collector ``` ## Manual Installation (without-Docker) diff --git a/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md b/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md index 225a94c..73eb4b0 100644 --- a/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md +++ b/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md @@ -43,7 +43,7 @@ docker run -it --rm \ --cap-add SYS_RAWIO \ --device=/dev/sda \ --device=/dev/sdb \ - analogj/scrutiny:collector smartctl --scan + ghcr.io/analogj/scrutiny:master-collector smartctl --scan ``` If the output is the same, your devices will be processed by Scrutiny. From 36617c8f1f7777b1e5a2289e951579be751e9226 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 22:25:45 -0700 Subject: [PATCH 074/114] using environmental variable in files path. --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 47e20e9..b7cbff4 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -43,7 +43,7 @@ jobs: - name: Generate coverage report uses: codecov/codecov-action@v2 with: - files: ./coverage.txt + files: $PROJECT_PATH/coverage.txt flags: unittests fail_ci_if_error: true verbose: true From 08f247109ad1086dc1a024ca521f77ffb4b4edde Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 30 Apr 2022 22:30:13 -0700 Subject: [PATCH 075/114] using environmental variable in files path. --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index b7cbff4..6e26655 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -43,7 +43,7 @@ jobs: - name: Generate coverage report uses: codecov/codecov-action@v2 with: - files: $PROJECT_PATH/coverage.txt + files: ${{ env.PROJECT_PATH }}/coverage.txt flags: unittests fail_ci_if_error: true verbose: true From ae99ffd57ece46a1a9af868548294a32fb94eab8 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 1 May 2022 21:08:18 -0700 Subject: [PATCH 076/114] using github container registry images. update documentation to enable persistence by default update docs to include influxdb --- README.md | 18 +++++++++++++----- docker/Vagrantfile | 2 ++ docker/docker-compose.yml | 3 ++- docs/INSTALL_MANUAL.md | 2 ++ docs/INSTALL_UNRAID.md | 6 +++--- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5172af6..b30f376 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ If you're using Docker, getting started is as simple as running the following co ```bash docker run -it --rm -p 8080:8080 \ + -v `pwd`/scrutiny:/scrutiny/config \ + -v `pwd`/influxdb2:/var/lib/influxdb2 \ -v /run/udev:/run/udev:ro \ --cap-add SYS_RAWIO \ --device=/dev/sda \ @@ -84,21 +86,27 @@ docker run -it --rm -p 8080:8080 \ - `--cap-add SYS_RAWIO` is necessary to allow `smartctl` permission to query your device SMART data - NOTE: If you have **NVMe** drives, you must add `--cap-add SYS_ADMIN` as well. See issue [#26](https://github.com/AnalogJ/scrutiny/issues/26#issuecomment-696817130) - `--device` entries are required to ensure that your hard disk devices are accessible within the container. -- `analogj/scrutiny` is a omnibus image, containing both the webapp server (frontend & api) as well as the S.M.A.R.T metric collector. (see below) +- `ghcr.io/analogj/scrutiny:master-omnibus` is a omnibus image, containing both the webapp server (frontend & api) as well as the S.M.A.R.T metric collector. (see below) ### Hub/Spoke Deployment In addition to the Omnibus image (available under the `latest` tag) there are 2 other Docker images available: -- `analogj/scrutiny:collector` - Contains the Scrutiny data collector, `smartctl` binary and cron-like scheduler. You can run one collector on each server. -- `analogj/scrutiny:web` - Contains the Web UI, API and Database. Only one container necessary +- `ghcr.io/analogj/scrutiny:master-collector` - Contains the Scrutiny data collector, `smartctl` binary and cron-like scheduler. You can run one collector on each server. +- `ghcr.io/analogj/scrutiny:master-web` - Contains the Web UI, API and Database. Only one container necessary ```bash -docker run -it --rm -p 8080:8080 \ +docker run --rm -p 8086:8086 \ + -v `pwd`/influxdb2:/var/lib/influxdb2 \ + --name scrutiny-web \ + influxdb:2.2 + +docker run --rm -p 8080:8080 \ + -v `pwd`/scrutiny:/scrutiny/config \ --name scrutiny-web \ ghcr.io/analogj/scrutiny:master-web -docker run -it --rm \ +docker run --rm \ -v /run/udev:/run/udev:ro \ --cap-add SYS_RAWIO \ --device=/dev/sda \ diff --git a/docker/Vagrantfile b/docker/Vagrantfile index 4efaf98..52310af 100644 --- a/docker/Vagrantfile +++ b/docker/Vagrantfile @@ -1,3 +1,5 @@ +# This vagrant file is only used for local development & testing. + Vagrant.configure("2") do |config| config.vm.guest = :freebsd config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", disabled: true diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 00e3abd..e610919 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -3,7 +3,7 @@ version: '3.5' services: scrutiny: container_name: scrutiny - image: analogj/scrutiny + image: ghcr.io/analogj/scrutiny:master-omnibus cap_add: - SYS_RAWIO ports: @@ -11,6 +11,7 @@ services: volumes: - /run/udev:/run/udev:ro - ./config:/scrutiny/config + - ./influxdb:/var/lib/influxdb2 devices: - "/dev/sda" - "/dev/sdb" diff --git a/docs/INSTALL_MANUAL.md b/docs/INSTALL_MANUAL.md index e6eb846..c6d26ec 100644 --- a/docs/INSTALL_MANUAL.md +++ b/docs/INSTALL_MANUAL.md @@ -132,6 +132,8 @@ chmod +x /opt/scrutiny/bin/scrutiny-collector-metrics-linux-amd64 Next, we will manually trigger the collector, to populate the Scrutiny dashboard: +> NOTE: if you need to pass a config file to the scrutiny collector, you can provide it using the `--config` flag. + ``` /opt/scrutiny/bin/scrutiny-collector-metrics-linux-amd64 run --api-endpoint "http://localhost:8080" ``` diff --git a/docs/INSTALL_UNRAID.md b/docs/INSTALL_UNRAID.md index 7a22aaf..f8b9fe4 100644 --- a/docs/INSTALL_UNRAID.md +++ b/docs/INSTALL_UNRAID.md @@ -19,13 +19,13 @@ To install, simply click 'Install'; the configuration parameters should not need As a docker image can be created using various OS bases, the image choice is entirely the users choice. Recommendations of a specific image from a specific maintainer is beyond the scope of this guide. However, to provide some context given the number of questions posed regarding the various versions available: -- **analogj/scrutiny** +- **ghcr.io/analogj/scrutiny:master-omnibus** - `Image maintained directly by the application author` - `Debian based docker image` -- **linuxserver/scrutiny:** +- **linuxserver/scrutiny** - `Image maintained by the LinuxServer.io group` - `Alpine based docker image` -- **hotio/scrutiny:** +- **hotio/scrutiny** - `Image maintained by hotio` - `DETAILS TBD` From 49c1ef6a37245adf8a9bf59627a5bf67cc1a8333 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 1 May 2022 21:15:04 -0700 Subject: [PATCH 077/114] fixing local persistent dir for influxdb in omnibus. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b30f376..d616b93 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ If you're using Docker, getting started is as simple as running the following co ```bash docker run -it --rm -p 8080:8080 \ -v `pwd`/scrutiny:/scrutiny/config \ - -v `pwd`/influxdb2:/var/lib/influxdb2 \ + -v `pwd`/influxdb2:/scrutiny/influxdb \ -v /run/udev:/run/udev:ro \ --cap-add SYS_RAWIO \ --device=/dev/sda \ @@ -98,7 +98,7 @@ In addition to the Omnibus image (available under the `latest` tag) there are 2 ```bash docker run --rm -p 8086:8086 \ -v `pwd`/influxdb2:/var/lib/influxdb2 \ - --name scrutiny-web \ + --name scrutiny-influxdb \ influxdb:2.2 docker run --rm -p 8080:8080 \ From 75de6ebfe09ae77616858a5089c35139683405a1 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 1 May 2022 22:01:34 -0700 Subject: [PATCH 078/114] addign ability to customize the scrutiny collector cron schedule using SCRUTINY_COLLECTOR_CRON_SCHEDULE env variable. similar to https://github.com/linuxserver/docker-scrutiny/pull/19 fixes https://github.com/linuxserver/docker-scrutiny/issues/17 fixes https://github.com/AnalogJ/scrutiny/issues/161 fixes https://github.com/AnalogJ/scrutiny/issues/66 fixes https://github.com/AnalogJ/scrutiny/issues/202 fixes https://github.com/AnalogJ/scrutiny/issues/121 --- docker/entrypoint-collector.sh | 4 ++++ rootfs/etc/cont-init.d/50-config | 4 ++++ rootfs/etc/cron.d/scrutiny | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 rootfs/etc/cont-init.d/50-config diff --git a/docker/entrypoint-collector.sh b/docker/entrypoint-collector.sh index 501c8d5..c94a67b 100755 --- a/docker/entrypoint-collector.sh +++ b/docker/entrypoint-collector.sh @@ -5,6 +5,10 @@ printenv | sed 's/^\(.*\)$/export \1/g' > /env.sh +# adding ability to customize the cron schedule. +SCRUTINY_COLLECTOR_CRON_SCHEDULE=${SCRUTINY_COLLECTOR_CRON_SCHEDULE:-"0 0 * * *"} +sed -i 's|{SCRUTINY_COLLECTOR_CRON_SCHEDULE}|'"${SCRUTINY_COLLECTOR_CRON_SCHEDULE}"'|g' /etc/cron.d/scrutiny + # now that we have the env start cron in the foreground echo "starting cron" su -c "cron -l 8 -f" root diff --git a/rootfs/etc/cont-init.d/50-config b/rootfs/etc/cont-init.d/50-config new file mode 100644 index 0000000..3c7cece --- /dev/null +++ b/rootfs/etc/cont-init.d/50-config @@ -0,0 +1,4 @@ +#!/usr/bin/with-contenv bash + +SCRUTINY_COLLECTOR_CRON_SCHEDULE=${SCRUTINY_COLLECTOR_CRON_SCHEDULE:-"0 0 * * *"} +sed -i 's|{SCRUTINY_COLLECTOR_CRON_SCHEDULE}|'"${SCRUTINY_COLLECTOR_CRON_SCHEDULE}"'|g' /etc/cron.d/scrutiny \ No newline at end of file diff --git a/rootfs/etc/cron.d/scrutiny b/rootfs/etc/cron.d/scrutiny index f464d04..9571f4b 100644 --- a/rootfs/etc/cron.d/scrutiny +++ b/rootfs/etc/cron.d/scrutiny @@ -11,5 +11,5 @@ MAILTO="" # correctly route collector logs (STDOUT & STDERR) to Cron foreground (collectable by Docker STDOUT) # cron schedule to run daily at midnight: '0 0 * * *' # System environmental variables are stripped by cron, source our dump of the docker environmental variables before each command (/env.sh) -0 0 * * * root . /env.sh; /scrutiny/bin/scrutiny-collector-metrics run >/proc/1/fd/1 2>/proc/1/fd/2 +{SCRUTINY_COLLECTOR_CRON_SCHEDULE} root . /env.sh; /scrutiny/bin/scrutiny-collector-metrics run >/proc/1/fd/1 2>/proc/1/fd/2 # An empty line is required at the end of this file for a valid cron file. From ce3d45e5432d244fa21de4a832e50e7fc8b124aa Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 1 May 2022 22:09:03 -0700 Subject: [PATCH 079/114] instructions in readme for how to override cron schedule. --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index d616b93..885b6b6 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,13 @@ There are two configuration files available: Neither file is required, however if provided, it allows you to configure how Scrutiny functions. +## Cron Schedule +Unfortunately the Cron schedule cannot be configured via the `collector.yaml` (as the collector binary needs to be trigged by a scheduler/cron). +However, if you are using the official `ghcr.io/analogj/scrutiny:master-collector` or `ghcr.io/analogj/scrutiny:master-omnibus` docker images, +you can use the `SCRUTINY_COLLECTOR_CRON_SCHEDULE` environmental variable to override the default cron schedule (daily @ midnight - `0 0 * * *`). + +`docker run -e SCRUTINY_COLLECTOR_CRON_SCHEDULE="0 0 * * *" ...` + ## Notifications Scrutiny supports sending SMART device failure notifications via the following services: From 646d0eff15ee009a848c3146cba4708a22a385ac Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sun, 1 May 2022 22:13:11 -0700 Subject: [PATCH 080/114] change the environmental variable to COLLECTOR_CRON_SCHEDULE --- README.md | 4 ++-- docker/entrypoint-collector.sh | 4 ++-- rootfs/etc/cont-init.d/50-config | 4 ++-- rootfs/etc/cron.d/scrutiny | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 885b6b6..e29e5c7 100644 --- a/README.md +++ b/README.md @@ -151,9 +151,9 @@ Neither file is required, however if provided, it allows you to configure how Sc ## Cron Schedule Unfortunately the Cron schedule cannot be configured via the `collector.yaml` (as the collector binary needs to be trigged by a scheduler/cron). However, if you are using the official `ghcr.io/analogj/scrutiny:master-collector` or `ghcr.io/analogj/scrutiny:master-omnibus` docker images, -you can use the `SCRUTINY_COLLECTOR_CRON_SCHEDULE` environmental variable to override the default cron schedule (daily @ midnight - `0 0 * * *`). +you can use the `COLLECTOR_CRON_SCHEDULE` environmental variable to override the default cron schedule (daily @ midnight - `0 0 * * *`). -`docker run -e SCRUTINY_COLLECTOR_CRON_SCHEDULE="0 0 * * *" ...` +`docker run -e COLLECTOR_CRON_SCHEDULE="0 0 * * *" ...` ## Notifications diff --git a/docker/entrypoint-collector.sh b/docker/entrypoint-collector.sh index c94a67b..69ed815 100755 --- a/docker/entrypoint-collector.sh +++ b/docker/entrypoint-collector.sh @@ -6,8 +6,8 @@ printenv | sed 's/^\(.*\)$/export \1/g' > /env.sh # adding ability to customize the cron schedule. -SCRUTINY_COLLECTOR_CRON_SCHEDULE=${SCRUTINY_COLLECTOR_CRON_SCHEDULE:-"0 0 * * *"} -sed -i 's|{SCRUTINY_COLLECTOR_CRON_SCHEDULE}|'"${SCRUTINY_COLLECTOR_CRON_SCHEDULE}"'|g' /etc/cron.d/scrutiny +COLLECTOR_CRON_SCHEDULE=${COLLECTOR_CRON_SCHEDULE:-"0 0 * * *"} +sed -i 's|{COLLECTOR_CRON_SCHEDULE}|'"${COLLECTOR_CRON_SCHEDULE}"'|g' /etc/cron.d/scrutiny # now that we have the env start cron in the foreground echo "starting cron" diff --git a/rootfs/etc/cont-init.d/50-config b/rootfs/etc/cont-init.d/50-config index 3c7cece..8ff0d45 100644 --- a/rootfs/etc/cont-init.d/50-config +++ b/rootfs/etc/cont-init.d/50-config @@ -1,4 +1,4 @@ #!/usr/bin/with-contenv bash -SCRUTINY_COLLECTOR_CRON_SCHEDULE=${SCRUTINY_COLLECTOR_CRON_SCHEDULE:-"0 0 * * *"} -sed -i 's|{SCRUTINY_COLLECTOR_CRON_SCHEDULE}|'"${SCRUTINY_COLLECTOR_CRON_SCHEDULE}"'|g' /etc/cron.d/scrutiny \ No newline at end of file +COLLECTOR_CRON_SCHEDULE=${COLLECTOR_CRON_SCHEDULE:-"0 0 * * *"} +sed -i 's|{COLLECTOR_CRON_SCHEDULE}|'"${COLLECTOR_CRON_SCHEDULE}"'|g' /etc/cron.d/scrutiny \ No newline at end of file diff --git a/rootfs/etc/cron.d/scrutiny b/rootfs/etc/cron.d/scrutiny index 9571f4b..f112b8e 100644 --- a/rootfs/etc/cron.d/scrutiny +++ b/rootfs/etc/cron.d/scrutiny @@ -11,5 +11,5 @@ MAILTO="" # correctly route collector logs (STDOUT & STDERR) to Cron foreground (collectable by Docker STDOUT) # cron schedule to run daily at midnight: '0 0 * * *' # System environmental variables are stripped by cron, source our dump of the docker environmental variables before each command (/env.sh) -{SCRUTINY_COLLECTOR_CRON_SCHEDULE} root . /env.sh; /scrutiny/bin/scrutiny-collector-metrics run >/proc/1/fd/1 2>/proc/1/fd/2 +{COLLECTOR_CRON_SCHEDULE} root . /env.sh; /scrutiny/bin/scrutiny-collector-metrics run >/proc/1/fd/1 2>/proc/1/fd/2 # An empty line is required at the end of this file for a valid cron file. From 97f6564c1e44ddd38d422e6899a6daf2110827f0 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Mon, 2 May 2022 10:26:25 -0700 Subject: [PATCH 081/114] adding documetnation for smartctl exit codes and addl test. --- collector/pkg/collector/base.go | 1 + collector/pkg/config/config_test.go | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/collector/pkg/collector/base.go b/collector/pkg/collector/base.go index ff1801f..3d4bdc9 100644 --- a/collector/pkg/collector/base.go +++ b/collector/pkg/collector/base.go @@ -40,6 +40,7 @@ func (c *BaseCollector) postJson(url string, body interface{}, target interface{ return json.NewDecoder(r.Body).Decode(target) } +// http://www.linuxguide.it/command_line/linux-manpage/do.php?file=smartctl#sect7 func (c *BaseCollector) LogSmartctlExitCode(exitCode int) { if exitCode&0x01 != 0 { c.logger.Errorln("smartctl could not parse commandline") diff --git a/collector/pkg/config/config_test.go b/collector/pkg/config/config_test.go index 1e8fd6d..8511c14 100644 --- a/collector/pkg/config/config_test.go +++ b/collector/pkg/config/config_test.go @@ -8,6 +8,19 @@ import ( "testing" ) +func TestConfiguration_InvalidConfigPath(t *testing.T) { + t.Parallel() + + //setup + testConfig, _ := config.Create() + + //test + err := testConfig.ReadConfig("does_not_exist.yaml") + + //assert + require.Error(t, err, "should return an error") +} + func TestConfiguration_GetScanOverrides_Simple(t *testing.T) { t.Parallel() From 9d85920f4906e2511fd5ac02f2eaed0d372779a7 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Tue, 3 May 2022 11:50:22 -0700 Subject: [PATCH 082/114] started working on migration code. --- go.mod | 2 + go.sum | 104 ++++++++++++++++++ .../migrations/m20201107210306/device.go | 30 +++++ .../migrations/m20201107210306/smart.go | 25 +++++ .../m20201107210306/smart_ata_attribute.go | 25 +++++ .../m20201107210306/smart_nvme_attribute.go | 21 ++++ .../m20201107210306/smart_scsci_attribute.go | 21 ++++ .../pkg/database/scrutiny_repository.go | 15 ++- .../scrutiny_repository_migrations.go | 96 ++++++++++++++++ 9 files changed, 337 insertions(+), 2 deletions(-) create mode 100644 webapp/backend/pkg/database/migrations/m20201107210306/device.go create mode 100644 webapp/backend/pkg/database/migrations/m20201107210306/smart.go create mode 100644 webapp/backend/pkg/database/migrations/m20201107210306/smart_ata_attribute.go create mode 100644 webapp/backend/pkg/database/migrations/m20201107210306/smart_nvme_attribute.go create mode 100644 webapp/backend/pkg/database/migrations/m20201107210306/smart_scsci_attribute.go create mode 100644 webapp/backend/pkg/database/scrutiny_repository_migrations.go diff --git a/go.mod b/go.mod index 1f4714d..fce6bc7 100644 --- a/go.mod +++ b/go.mod @@ -7,11 +7,13 @@ require ( github.com/containrrr/shoutrrr v0.4.4 github.com/fatih/color v1.10.0 github.com/gin-gonic/gin v1.6.3 + github.com/go-gormigrate/gormigrate/v2 v2.0.0 github.com/golang/mock v1.4.3 github.com/google/uuid v1.2.0 // indirect github.com/hashicorp/serf v0.8.2 // indirect github.com/influxdata/influxdb-client-go/v2 v2.2.3 github.com/jaypipes/ghw v0.6.1 + github.com/jinzhu/gorm v1.9.16 github.com/klauspost/compress v1.12.1 // indirect github.com/kvz/logstreamer v0.0.0-20150507115422-a635b98146f0 // indirect github.com/mattn/go-sqlite3 v1.14.4 // indirect diff --git a/go.sum b/go.sum index 8ea4b43..f30e6c4 100644 --- a/go.sum +++ b/go.sum @@ -15,6 +15,7 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/agnivade/wasmbrowsertest v0.3.1/go.mod h1:zQt6ZTdl338xxRaMW395qccVE2eQm0SjC/SDz0mPWQI= @@ -22,6 +23,7 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/analogj/go-util v0.0.0-20190301173314-5295e364eb14 h1:wsrSjiqQtseStRIoLLxS4C5IEtXkazZVEPDHq8jW7r8= github.com/analogj/go-util v0.0.0-20190301173314-5295e364eb14/go.mod h1:lJQVqFKMV5/oDGYR2bra2OljcF3CvolAoyDRyOA4k4E= +github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= @@ -39,6 +41,7 @@ github.com/chromedp/cdproto v0.0.0-20190926234355-1b4886c6fad6/go.mod h1:0YChpVz github.com/chromedp/chromedp v0.3.1-0.20190619195644-fd957a4d2901/go.mod h1:mJdvfrVn594N9tfiPecUidF6W5jPRKHymqHfzbobPsM= github.com/chromedp/chromedp v0.4.0/go.mod h1:DC3QUn4mJ24dwjcaGQLoZrhm4X/uPHZ6spDbS2uFhm4= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/containrrr/shoutrrr v0.0.0-20200828202222-1da53231b05a h1:6ZMiughZYF6fJjFIf2X3D7AfImJeXnTMJ9qC2v75WPw= github.com/containrrr/shoutrrr v0.0.0-20200828202222-1da53231b05a/go.mod h1:z3pUtEhu5zOpu+Q8wZWiEq+ZLL9hM0HiFNhttaI67Ks= github.com/containrrr/shoutrrr v0.4.4 h1:vHZ4E/76pKVY+Jyn/qhBz3X540Bn8NI5ppPHK4PyILY= @@ -49,20 +52,25 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deepmap/oapi-codegen v1.3.13 h1:9HKGCsdJqE4dnrQ8VerFS0/1ZOJPmAhN+g8xgp8y3K4= github.com/deepmap/oapi-codegen v1.3.13/go.mod h1:WAmG5dWY8/PYHt4vKxlt90NsbHMAOCiteYKZMiIRfOo= +github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= @@ -82,6 +90,8 @@ github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gormigrate/gormigrate/v2 v2.0.0 h1:e2A3Uznk4viUC4UuemuVgsNnvYZyOA8B3awlYk3UioU= +github.com/go-gormigrate/gormigrate/v2 v2.0.0/go.mod h1:YuVJ+D/dNt4HWrThTBnjgZuRbt7AuwINeg4q52ZE3Jw= github.com/go-interpreter/wagon v0.5.1-0.20190713202023-55a163980b6c/go.mod h1:5+b/MBYkclRZngKF5s6qrgWxSLgE9F5dFdO1hAueZLc= github.com/go-interpreter/wagon v0.6.0/go.mod h1:5+b/MBYkclRZngKF5s6qrgWxSLgE9F5dFdO1hAueZLc= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -97,13 +107,16 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87 github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -193,6 +206,46 @@ github.com/influxdata/influxdb-client-go/v2 v2.2.3 h1:082jdJ5t1CFeo0rpGQvKAK1mON github.com/influxdata/influxdb-client-go/v2 v2.2.3/go.mod h1:fa/d1lAdUHxuc1jedx30ZfNG573oQTQmUni3N6pcW+0= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= +github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= +github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= +github.com/jackc/pgconn v1.6.4/go.mod h1:w2pne1C2tZgP+TvjqLpOigGzNqjBgQW9dUw/4Chex78= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.0.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= +github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= +github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= +github.com/jackc/pgtype v1.4.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= +github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= +github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= +github.com/jackc/pgx/v4 v4.8.1/go.mod h1:4HOLxrl8wToZJReD04/yB20GDwf4KBYETvlHciCnwW0= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jarcoal/httpmock v1.0.4 h1:jp+dy/+nonJE4g4xbVtl9QdrUNbn6/3hDT5R4nDIZnA= github.com/jarcoal/httpmock v1.0.4/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jaypipes/ghw v0.6.1 h1:Ewt3mdpiyhWotGyzg1ursV/6SnToGcG4215X6rR2af8= @@ -200,10 +253,14 @@ github.com/jaypipes/ghw v0.6.1/go.mod h1:QOXppNRCLGYR1H+hu09FxZPqjNt09bqUZUnOL3R github.com/jaypipes/pcidb v0.5.0 h1:4W5gZ+G7QxydevI8/MmmKdnIPJpURqJ2JNXTzfLxF5c= github.com/jaypipes/pcidb v0.5.0/go.mod h1:L2RGk04sfRhp5wvHO0gfRAMoLY/F3PKv/nwJeVoho0o= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= +github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= @@ -228,6 +285,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kvz/logstreamer v0.0.0-20150507115422-a635b98146f0 h1:3tLzEnUizyN9YLWFTT9loC30lSBvh2y70LTDcZOTs1s= @@ -236,6 +294,11 @@ github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvf github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -246,18 +309,23 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/mattn/go-sqlite3 v1.14.3 h1:j7a/xn1U6TKA/PHHxqZuzh64CdtRc7rU9M+AvkOl5bA= github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/mattn/go-sqlite3 v1.14.4 h1:4rQjbDxdu9fSgI/r3KN72G3c2goxknAqHHgPWWs8UlI= @@ -327,16 +395,23 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -371,6 +446,7 @@ github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -393,22 +469,33 @@ github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.coder.com/go-tools v0.0.0-20190317003359-0c6a35b74a16/go.mod h1:iKV5yK9t+J5nG9O3uF6KYdPEz3dyfMyB15MN1rbQ8Qw= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180426230345-b49d69b5da94/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= @@ -432,6 +519,7 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -449,7 +537,9 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -479,6 +569,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190306220234-b354f8bf4d9e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -488,6 +579,7 @@ golang.org/x/sys v0.0.0-20190618155005-516e3c20635f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190927073244-c990c680b611/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -527,18 +619,23 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -584,6 +681,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ= @@ -598,8 +696,14 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gorm.io/driver/mysql v1.0.1/go.mod h1:KtqSthtg55lFp3S5kUXqlGaelnWpKitn4k1xZTnoiPw= +gorm.io/driver/postgres v1.0.0/go.mod h1:wtMFcOzmuA5QigNsgEIb7O5lhvH1tHAF1RbWmLWV4to= +gorm.io/driver/sqlite v1.1.1/go.mod h1:hm2olEcl8Tmsc6eZyxYSeznnsDaMqamBvEXLNtBg4cI= gorm.io/driver/sqlite v1.1.3 h1:BYfdVuZB5He/u9dt4qDpZqiqDJ6KhPqs5QUqsr/Eeuc= gorm.io/driver/sqlite v1.1.3/go.mod h1:AKDgRWk8lcSQSw+9kxCJnX/yySj8G3rdwYlU57cB45c= +gorm.io/driver/sqlserver v1.0.2/go.mod h1:gb0Y9QePGgqjzrVyTQUZeh9zkd5v0iz71cM1B4ZycEY= +gorm.io/gorm v1.9.19/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/gorm v1.20.0/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.20.1/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.20.2 h1:bZzSEnq7NDGsrd+n3evOOedDrY5oLM5QPlCjZJUK2ro= gorm.io/gorm v1.20.2/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= diff --git a/webapp/backend/pkg/database/migrations/m20201107210306/device.go b/webapp/backend/pkg/database/migrations/m20201107210306/device.go new file mode 100644 index 0000000..250122d --- /dev/null +++ b/webapp/backend/pkg/database/migrations/m20201107210306/device.go @@ -0,0 +1,30 @@ +package m20201107210306 + +import ( + "time" +) + +type Device struct { + //GORM attributes, see: http://gorm.io/docs/conventions.html + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt *time.Time + + WWN string `json:"wwn" gorm:"primary_key"` + HostId string `json:"host_id"` + + DeviceName string `json:"device_name"` + Manufacturer string `json:"manufacturer"` + ModelName string `json:"model_name"` + InterfaceType string `json:"interface_type"` + InterfaceSpeed string `json:"interface_speed"` + SerialNumber string `json:"serial_number"` + Firmware string `json:"firmware"` + RotationSpeed int `json:"rotational_speed"` + Capacity int64 `json:"capacity"` + FormFactor string `json:"form_factor"` + SmartSupport bool `json:"smart_support"` + DeviceProtocol string `json:"device_protocol"` //protocol determines which smart attribute types are available (ATA, NVMe, SCSI) + DeviceType string `json:"device_type"` //device type is used for querying with -d/t flag, should only be used by collector. + SmartResults []Smart `gorm:"foreignkey:DeviceWWN" json:"smart_results"` +} diff --git a/webapp/backend/pkg/database/migrations/m20201107210306/smart.go b/webapp/backend/pkg/database/migrations/m20201107210306/smart.go new file mode 100644 index 0000000..798da4d --- /dev/null +++ b/webapp/backend/pkg/database/migrations/m20201107210306/smart.go @@ -0,0 +1,25 @@ +package m20201107210306 + +import ( + "gorm.io/gorm" + "time" +) + +type Smart struct { + gorm.Model + + DeviceWWN string `json:"device_wwn"` + Device Device `json:"-" gorm:"foreignkey:DeviceWWN"` // use DeviceWWN as foreign key + + TestDate time.Time `json:"date"` + SmartStatus string `json:"smart_status"` // SmartStatusPassed or SmartStatusFailed + + //Metrics + Temp int64 `json:"temp"` + PowerOnHours int64 `json:"power_on_hours"` + PowerCycleCount int64 `json:"power_cycle_count"` + + AtaAttributes []SmartAtaAttribute `json:"ata_attributes" gorm:"foreignkey:SmartId"` + NvmeAttributes []SmartNvmeAttribute `json:"nvme_attributes" gorm:"foreignkey:SmartId"` + ScsiAttributes []SmartScsiAttribute `json:"scsi_attributes" gorm:"foreignkey:SmartId"` +} diff --git a/webapp/backend/pkg/database/migrations/m20201107210306/smart_ata_attribute.go b/webapp/backend/pkg/database/migrations/m20201107210306/smart_ata_attribute.go new file mode 100644 index 0000000..f1f10dd --- /dev/null +++ b/webapp/backend/pkg/database/migrations/m20201107210306/smart_ata_attribute.go @@ -0,0 +1,25 @@ +package m20201107210306 + +import "gorm.io/gorm" + +type SmartAtaAttribute struct { + gorm.Model + + SmartId int `json:"smart_id"` + Smart Device `json:"-" gorm:"foreignkey:SmartId"` // use SmartId as foreign key + + AttributeId int `json:"attribute_id"` + Name string `json:"name"` + Value int `json:"value"` + Worst int `json:"worst"` + Threshold int `json:"thresh"` + RawValue int64 `json:"raw_value"` + RawString string `json:"raw_string"` + WhenFailed string `json:"when_failed"` + + TransformedValue int64 `json:"transformed_value"` + Status string `gorm:"-" json:"status,omitempty"` + StatusReason string `gorm:"-" json:"status_reason,omitempty"` + FailureRate float64 `gorm:"-" json:"failure_rate,omitempty"` + History []SmartAtaAttribute `gorm:"-" json:"history,omitempty"` +} diff --git a/webapp/backend/pkg/database/migrations/m20201107210306/smart_nvme_attribute.go b/webapp/backend/pkg/database/migrations/m20201107210306/smart_nvme_attribute.go new file mode 100644 index 0000000..97abdad --- /dev/null +++ b/webapp/backend/pkg/database/migrations/m20201107210306/smart_nvme_attribute.go @@ -0,0 +1,21 @@ +package m20201107210306 + +import "gorm.io/gorm" + +type SmartNvmeAttribute struct { + gorm.Model + + SmartId int `json:"smart_id"` + Smart Device `json:"-" gorm:"foreignkey:SmartId"` // use SmartId as foreign key + + AttributeId string `json:"attribute_id"` //json string from smartctl + Name string `json:"name"` + Value int `json:"value"` + Threshold int `json:"thresh"` + + TransformedValue int64 `json:"transformed_value"` + Status string `gorm:"-" json:"status,omitempty"` + StatusReason string `gorm:"-" json:"status_reason,omitempty"` + FailureRate float64 `gorm:"-" json:"failure_rate,omitempty"` + History []SmartNvmeAttribute `gorm:"-" json:"history,omitempty"` +} diff --git a/webapp/backend/pkg/database/migrations/m20201107210306/smart_scsci_attribute.go b/webapp/backend/pkg/database/migrations/m20201107210306/smart_scsci_attribute.go new file mode 100644 index 0000000..4b2df5e --- /dev/null +++ b/webapp/backend/pkg/database/migrations/m20201107210306/smart_scsci_attribute.go @@ -0,0 +1,21 @@ +package m20201107210306 + +import "gorm.io/gorm" + +type SmartScsiAttribute struct { + gorm.Model + + SmartId int `json:"smart_id"` + Smart Device `json:"-" gorm:"foreignkey:SmartId"` // use SmartId as foreign key + + AttributeId string `json:"attribute_id"` //json string from smartctl + Name string `json:"name"` + Value int `json:"value"` + Threshold int `json:"thresh"` + + TransformedValue int64 `json:"transformed_value"` + Status string `gorm:"-" json:"status,omitempty"` + StatusReason string `gorm:"-" json:"status_reason,omitempty"` + FailureRate float64 `gorm:"-" json:"failure_rate,omitempty"` + History []SmartScsiAttribute `gorm:"-" json:"history,omitempty"` +} diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index f442a20..41b89aa 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -57,17 +57,18 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Gorm/SQLite setup //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - fmt.Printf("Trying to connect to database stored: %s\n", appConfig.GetString("web.database.location")) + globalLogger.Infof("Trying to connect to scrutiny sqlite db: %s\n", appConfig.GetString("web.database.location")) database, err := gorm.Open(sqlite.Open(appConfig.GetString("web.database.location")), &gorm.Config{ //TODO: figure out how to log database queries again. //Logger: logger + DisableForeignKeyConstraintWhenMigrating: true, }) if err != nil { return nil, fmt.Errorf("Failed to connect to database! - %v", err) } + globalLogger.Infof("Successfully connected to scrutiny sqlite db: %s\n", appConfig.GetString("web.database.location")) //database.SetLogger() - database.AutoMigrate(&models.Device{}) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // InfluxDB setup @@ -143,6 +144,16 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field if err != nil { return nil, err } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // InfluxDB & SQLite migrations + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //database.AutoMigrate(&models.Device{}) + err = deviceRepo.Migrate(backgroundContext) + if err != nil { + return nil, err + } + return &deviceRepo, nil } diff --git a/webapp/backend/pkg/database/scrutiny_repository_migrations.go b/webapp/backend/pkg/database/scrutiny_repository_migrations.go new file mode 100644 index 0000000..0e299fa --- /dev/null +++ b/webapp/backend/pkg/database/scrutiny_repository_migrations.go @@ -0,0 +1,96 @@ +package database + +import ( + "context" + "github.com/analogj/scrutiny/webapp/backend/pkg/database/migrations/m20201107210306" + "github.com/analogj/scrutiny/webapp/backend/pkg/models" + "github.com/go-gormigrate/gormigrate/v2" + _ "github.com/jinzhu/gorm/dialects/sqlite" + "gorm.io/gorm" +) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SQLite migrations +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//database.AutoMigrate(&models.Device{}) + +func (sr *scrutinyRepository) Migrate(ctx context.Context) error { + + sr.logger.Infoln("Database migration starting") + + m := gormigrate.New(sr.gormClient, gormigrate.DefaultOptions, []*gormigrate.Migration{ + { + ID: "20201107210306", // v0.3.13 (pre-influxdb schema). 9fac3c6308dc6cb6cd5bbc43a68cd93e8fb20b87 + Migrate: func(tx *gorm.DB) error { + // it's a good practice to copy the struct inside the function, + + return tx.AutoMigrate( + &m20201107210306.Device{}, + &m20201107210306.Smart{}, + &m20201107210306.SmartAtaAttribute{}, + &m20201107210306.SmartNvmeAttribute{}, + &m20201107210306.SmartNvmeAttribute{}, + ) + }, + Rollback: func(tx *gorm.DB) error { + return tx.Migrator().DropTable( + &m20201107210306.Device{}, + &m20201107210306.Smart{}, + &m20201107210306.SmartAtaAttribute{}, + &m20201107210306.SmartNvmeAttribute{}, + &m20201107210306.SmartNvmeAttribute{}, + "self_tests", + ) + }, + }, + { + ID: "20220503113100", // backwards compatible - influxdb schema + Migrate: func(tx *gorm.DB) error { + // delete unnecessary table. + err := tx.Migrator().DropTable("self_tests") + if err != nil { + return err + } + + //add columns to the Device schema, so we can start adding data to the database & influxdb + err = tx.Migrator().AddColumn(&models.Device{}, "Label") //Label string `json:"label"` + if err != nil { + return err + } + err = tx.Migrator().AddColumn(&models.Device{}, "DeviceStatus") //DeviceStatus pkg.DeviceStatus `json:"device_status"` + if err != nil { + return err + } + + //TODO: migrate the data from GORM to influxdb. + + return nil + }, + }, + //{ + // ID: "20220503120000", // v0.4.0 - influxdb schema + // Migrate: func(tx *gorm.DB) error { + // // delete unnecessary tables. + // err := tx.Migrator().DropTable( + // &m20201107210306.Smart{}, + // &m20201107210306.SmartAtaAttribute{}, + // &m20201107210306.SmartNvmeAttribute{}, + // &m20201107210306.SmartNvmeAttribute{}, + // ) + // if err != nil { + // return err + // } + // + // //migrate the device database to the final version + // return tx.AutoMigrate(models.Device{}) + // }, + //}, + }) + + if err := m.Migrate(); err != nil { + sr.logger.Errorf("Database migration failed with error: %w", err) + return err + } + sr.logger.Infoln("Database migration completed successfully") + return nil +} From 2750ccef4aff529f194aab2eaf0b91eadecf4970 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Tue, 3 May 2022 11:52:47 -0700 Subject: [PATCH 083/114] call out deprecated structs so they are not accidentally used via autocomplete. --- webapp/backend/pkg/database/migrations/m20201107210306/device.go | 1 + webapp/backend/pkg/database/migrations/m20201107210306/smart.go | 1 + .../database/migrations/m20201107210306/smart_ata_attribute.go | 1 + .../database/migrations/m20201107210306/smart_nvme_attribute.go | 1 + .../database/migrations/m20201107210306/smart_scsci_attribute.go | 1 + 5 files changed, 5 insertions(+) diff --git a/webapp/backend/pkg/database/migrations/m20201107210306/device.go b/webapp/backend/pkg/database/migrations/m20201107210306/device.go index 250122d..cac8b29 100644 --- a/webapp/backend/pkg/database/migrations/m20201107210306/device.go +++ b/webapp/backend/pkg/database/migrations/m20201107210306/device.go @@ -4,6 +4,7 @@ import ( "time" ) +// Deprecated: m20201107210306.Device is deprecated, only used by db migrations type Device struct { //GORM attributes, see: http://gorm.io/docs/conventions.html CreatedAt time.Time diff --git a/webapp/backend/pkg/database/migrations/m20201107210306/smart.go b/webapp/backend/pkg/database/migrations/m20201107210306/smart.go index 798da4d..f0e615b 100644 --- a/webapp/backend/pkg/database/migrations/m20201107210306/smart.go +++ b/webapp/backend/pkg/database/migrations/m20201107210306/smart.go @@ -5,6 +5,7 @@ import ( "time" ) +// Deprecated: m20201107210306.Smart is deprecated, only used by db migrations type Smart struct { gorm.Model diff --git a/webapp/backend/pkg/database/migrations/m20201107210306/smart_ata_attribute.go b/webapp/backend/pkg/database/migrations/m20201107210306/smart_ata_attribute.go index f1f10dd..d20bac4 100644 --- a/webapp/backend/pkg/database/migrations/m20201107210306/smart_ata_attribute.go +++ b/webapp/backend/pkg/database/migrations/m20201107210306/smart_ata_attribute.go @@ -2,6 +2,7 @@ package m20201107210306 import "gorm.io/gorm" +// Deprecated: m20201107210306.SmartAtaAttribute is deprecated, only used by db migrations type SmartAtaAttribute struct { gorm.Model diff --git a/webapp/backend/pkg/database/migrations/m20201107210306/smart_nvme_attribute.go b/webapp/backend/pkg/database/migrations/m20201107210306/smart_nvme_attribute.go index 97abdad..3fe944a 100644 --- a/webapp/backend/pkg/database/migrations/m20201107210306/smart_nvme_attribute.go +++ b/webapp/backend/pkg/database/migrations/m20201107210306/smart_nvme_attribute.go @@ -2,6 +2,7 @@ package m20201107210306 import "gorm.io/gorm" +// Deprecated: m20201107210306.SmartNvmeAttribute is deprecated, only used by db migrations type SmartNvmeAttribute struct { gorm.Model diff --git a/webapp/backend/pkg/database/migrations/m20201107210306/smart_scsci_attribute.go b/webapp/backend/pkg/database/migrations/m20201107210306/smart_scsci_attribute.go index 4b2df5e..2a5be46 100644 --- a/webapp/backend/pkg/database/migrations/m20201107210306/smart_scsci_attribute.go +++ b/webapp/backend/pkg/database/migrations/m20201107210306/smart_scsci_attribute.go @@ -2,6 +2,7 @@ package m20201107210306 import "gorm.io/gorm" +// Deprecated: m20201107210306.SmartScsiAttribute is deprecated, only used by db migrations type SmartScsiAttribute struct { gorm.Model From 7d963c96a6aaa43714637175b9e5e5b0f51c320b Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Tue, 3 May 2022 12:03:08 -0700 Subject: [PATCH 084/114] writing pseudocode algorithm for data migration. --- .../pkg/database/scrutiny_repository_migrations.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/webapp/backend/pkg/database/scrutiny_repository_migrations.go b/webapp/backend/pkg/database/scrutiny_repository_migrations.go index 0e299fa..c7cedd2 100644 --- a/webapp/backend/pkg/database/scrutiny_repository_migrations.go +++ b/webapp/backend/pkg/database/scrutiny_repository_migrations.go @@ -63,12 +63,22 @@ func (sr *scrutinyRepository) Migrate(ctx context.Context) error { } //TODO: migrate the data from GORM to influxdb. - + //get a list of all devices: + // get a list of all smart scans in the last 2 weeks: + // get a list of associated smart attribute data: + // translate to a collector.SmartInfo object + // call scrutinyRepository.SaveSmartAttributes + // get a list of all smart scans in the last 9 weeks: + // do same as above (select 1 scan per week) + // get a list of all smart scans in the last 25 months: + // do same as above (select 1 scan per month) + // get a list of all smart scans: + // do same as above (select 1 scan per year) return nil }, }, //{ - // ID: "20220503120000", // v0.4.0 - influxdb schema + // ID: "20220503120000", // cleanup - v0.4.0 - influxdb schema // Migrate: func(tx *gorm.DB) error { // // delete unnecessary tables. // err := tx.Migrator().DropTable( From 8fe0dbed6baa05ed5c425a41679c2816c407d7b8 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Tue, 3 May 2022 22:40:31 -0700 Subject: [PATCH 085/114] partially working. Some datapoints are failing with panic and are silently ignored. TODO must fix. --- .../migrations/m20201107210306/device.go | 16 + ...tiny_repository_device_smart_attributes.go | 19 +- .../scrutiny_repository_migrations.go | 345 +++++++++++++++++- webapp/backend/pkg/models/collector/smart.go | 139 +++---- .../backend/pkg/models/measurements/smart.go | 72 ++-- 5 files changed, 482 insertions(+), 109 deletions(-) diff --git a/webapp/backend/pkg/database/migrations/m20201107210306/device.go b/webapp/backend/pkg/database/migrations/m20201107210306/device.go index cac8b29..11600c3 100644 --- a/webapp/backend/pkg/database/migrations/m20201107210306/device.go +++ b/webapp/backend/pkg/database/migrations/m20201107210306/device.go @@ -29,3 +29,19 @@ type Device struct { DeviceType string `json:"device_type"` //device type is used for querying with -d/t flag, should only be used by collector. SmartResults []Smart `gorm:"foreignkey:DeviceWWN" json:"smart_results"` } + +const DeviceProtocolAta = "ATA" +const DeviceProtocolScsi = "SCSI" +const DeviceProtocolNvme = "NVMe" + +func (dv *Device) IsAta() bool { + return dv.DeviceProtocol == DeviceProtocolAta +} + +func (dv *Device) IsScsi() bool { + return dv.DeviceProtocol == DeviceProtocolScsi +} + +func (dv *Device) IsNvme() bool { + return dv.DeviceProtocol == DeviceProtocolNvme +} diff --git a/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go b/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go index 263e08d..19d5861 100644 --- a/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go +++ b/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go @@ -6,8 +6,10 @@ import ( "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" influxdb2 "github.com/influxdata/influxdb-client-go/v2" + "github.com/influxdata/influxdb-client-go/v2/api" log "github.com/sirupsen/logrus" "strings" + "time" ) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -22,13 +24,9 @@ func (sr *scrutinyRepository) SaveSmartAttributes(ctx context.Context, wwn strin } tags, fields := deviceSmartData.Flatten() - p := influxdb2.NewPoint("smart", - tags, - fields, - deviceSmartData.Date) // write point immediately - return deviceSmartData, sr.influxWriteApi.WritePoint(ctx, p) + return deviceSmartData, sr.saveDatapoint(sr.influxWriteApi, "smart", tags, fields, deviceSmartData.Date, ctx) } func (sr *scrutinyRepository) GetSmartAttributeHistory(ctx context.Context, wwn string, durationKey string, attributes []string) ([]measurements.Smart, error) { @@ -93,6 +91,17 @@ func (sr *scrutinyRepository) GetSmartAttributeHistory(ctx context.Context, wwn // Helper Methods //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +func (sr *scrutinyRepository) saveDatapoint(influxWriteApi api.WriteAPIBlocking, measurement string, tags map[string]string, fields map[string]interface{}, date time.Time, ctx context.Context) error { + sr.logger.Debugf("Storing datapoint in measurement '%s'. tags: %d fields: %d", measurement, len(tags), len(fields)) + p := influxdb2.NewPoint(measurement, + tags, + fields, + date) + + // write point immediately + return influxWriteApi.WritePoint(ctx, p) +} + func (sr *scrutinyRepository) aggregateSmartAttributesQuery(wwn string, durationKey string) string { /* diff --git a/webapp/backend/pkg/database/scrutiny_repository_migrations.go b/webapp/backend/pkg/database/scrutiny_repository_migrations.go index c7cedd2..0c12186 100644 --- a/webapp/backend/pkg/database/scrutiny_repository_migrations.go +++ b/webapp/backend/pkg/database/scrutiny_repository_migrations.go @@ -2,11 +2,16 @@ package database import ( "context" + "fmt" "github.com/analogj/scrutiny/webapp/backend/pkg/database/migrations/m20201107210306" "github.com/analogj/scrutiny/webapp/backend/pkg/models" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" "github.com/go-gormigrate/gormigrate/v2" _ "github.com/jinzhu/gorm/dialects/sqlite" "gorm.io/gorm" + "strconv" + "time" ) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -66,14 +71,170 @@ func (sr *scrutinyRepository) Migrate(ctx context.Context) error { //get a list of all devices: // get a list of all smart scans in the last 2 weeks: // get a list of associated smart attribute data: - // translate to a collector.SmartInfo object - // call scrutinyRepository.SaveSmartAttributes + // translate to a measurements.Smart{} object + // call CUSTOM INFLUXDB SAVE FUNCTION (taking bucket as parameter) // get a list of all smart scans in the last 9 weeks: // do same as above (select 1 scan per week) // get a list of all smart scans in the last 25 months: // do same as above (select 1 scan per month) // get a list of all smart scans: // do same as above (select 1 scan per year) + + preDevices := []m20201107210306.Device{} //pre-migration device information + if err = tx.Preload("SmartResults", func(db *gorm.DB) *gorm.DB { + return db.Order("smarts.created_at ASC") //OLD: .Limit(devicesCount) + }).Find(&preDevices).Error; err != nil { + sr.logger.Errorln("Could not get device summary from DB", err) + return err + } + + //weekly, monthly, yearly lookup storage, so we don't add more data to the buckets than necessary. + weeklyLookup := map[string]bool{} + monthlyLookup := map[string]bool{} + yearlyLookup := map[string]bool{} + + //calculate bucket oldest dates + today := time.Now() + dailyBucketMax := today.Add(-RETENTION_PERIOD_15_DAYS_IN_SECONDS * time.Second) //15 days + weeklyBucketMax := today.Add(-RETENTION_PERIOD_9_WEEKS_IN_SECONDS * time.Second) //9 weeks + monthlyBucketMax := today.Add(-RETENTION_PERIOD_25_MONTHS_IN_SECONDS * time.Second) //25 weeks + + for _, preDevice := range preDevices { + for _, preSmartResult := range preDevice.SmartResults { //pre-migration smart results + + //we're looping in ASC mode, so from oldest entry to most current. + + //TODO: skip any results that are outside of the range that we care about for each bucket. + + err, postSmartResults := m20201107210306_FromPreInfluxDBSmartResultsCreatePostInfluxDBSmartResults(tx, preDevice, preSmartResult) + if err != nil { + return err + } + smartTags, smartFields := postSmartResults.Flatten() + + err, postSmartTemp := m20201107210306_FromPreInfluxDBTempCreatePostInfluxDBTemp(preDevice, preSmartResult) + if err != nil { + return err + } + tempTags, tempFields := postSmartTemp.Flatten() + tempTags["device_wwn"] = preDevice.WWN + + year, week := postSmartResults.Date.ISOWeek() + month := postSmartResults.Date.Month() + + yearStr := strconv.Itoa(year) + yearMonthStr := fmt.Sprintf("%d-%d", year, month) + yearWeekStr := fmt.Sprintf("%d-%d", year, week) + + //write data to daily bucket if in the last 15 days + if postSmartResults.Date.After(dailyBucketMax) { + sr.logger.Debugf("device (%s) smart data added to bucket: daily", preDevice.WWN) + // write point immediately + err = sr.saveDatapoint( + sr.influxClient.WriteAPIBlocking(sr.appConfig.GetString("web.influxdb.org"), sr.appConfig.GetString("web.influxdb.bucket")), + "smart", + smartTags, + smartFields, + postSmartResults.Date, ctx) + if err != nil { + return err + } + + err = sr.saveDatapoint( + sr.influxClient.WriteAPIBlocking(sr.appConfig.GetString("web.influxdb.org"), sr.appConfig.GetString("web.influxdb.bucket")), + "temp", + tempTags, + tempFields, + postSmartResults.Date, ctx) + if err != nil { + return err + } + } + + //write data to the weekly bucket if in the last 9 weeks, and week has not been processed yet + if _, weekExists := weeklyLookup[yearWeekStr]; !weekExists && postSmartResults.Date.After(weeklyBucketMax) { + sr.logger.Debugf("device (%s) smart data added to bucket: weekly", preDevice.WWN) + + //this week/year pair has not been processed + weeklyLookup[yearWeekStr] = true + // write point immediately + err = sr.saveDatapoint( + sr.influxClient.WriteAPIBlocking(sr.appConfig.GetString("web.influxdb.org"), fmt.Sprintf("%s_weekly", sr.appConfig.GetString("web.influxdb.bucket"))), + "smart", + smartTags, + smartFields, + postSmartResults.Date, ctx) + + if err != nil { + return err + } + + err = sr.saveDatapoint( + sr.influxClient.WriteAPIBlocking(sr.appConfig.GetString("web.influxdb.org"), fmt.Sprintf("%s_weekly", sr.appConfig.GetString("web.influxdb.bucket"))), + "temp", + tempTags, + tempFields, + postSmartResults.Date, ctx) + if err != nil { + return err + } + } + + //write data to the monthly bucket if in the last 9 weeks, and week has not been processed yet + if _, monthExists := monthlyLookup[yearMonthStr]; !monthExists && postSmartResults.Date.After(monthlyBucketMax) { + sr.logger.Debugf("device (%s) smart data added to bucket: monthly", preDevice.WWN) + //this month/year pair has not been processed + monthlyLookup[yearMonthStr] = true + // write point immediately + err = sr.saveDatapoint( + sr.influxClient.WriteAPIBlocking(sr.appConfig.GetString("web.influxdb.org"), fmt.Sprintf("%s_monthly", sr.appConfig.GetString("web.influxdb.bucket"))), + "smart", + smartTags, + smartFields, + postSmartResults.Date, ctx) + if err != nil { + return err + } + + err = sr.saveDatapoint( + sr.influxClient.WriteAPIBlocking(sr.appConfig.GetString("web.influxdb.org"), fmt.Sprintf("%s_monthly", sr.appConfig.GetString("web.influxdb.bucket"))), + "temp", + tempTags, + tempFields, + postSmartResults.Date, ctx) + if err != nil { + return err + } + } + + if _, yearExists := yearlyLookup[yearStr]; !yearExists && year != today.Year() { + sr.logger.Debugf("device (%s) smart data added to bucket: yearly", preDevice.WWN) + //this year has not been processed + yearlyLookup[yearStr] = true + // write point immediately + err = sr.saveDatapoint( + sr.influxClient.WriteAPIBlocking(sr.appConfig.GetString("web.influxdb.org"), fmt.Sprintf("%s_yearly", sr.appConfig.GetString("web.influxdb.bucket"))), + "smart", + smartTags, + smartFields, + postSmartResults.Date, ctx) + if err != nil { + return err + } + + err = sr.saveDatapoint( + sr.influxClient.WriteAPIBlocking(sr.appConfig.GetString("web.influxdb.org"), fmt.Sprintf("%s_yearly", sr.appConfig.GetString("web.influxdb.bucket"))), + "temp", + tempTags, + tempFields, + postSmartResults.Date, ctx) + if err != nil { + return err + } + } + } + } + return nil }, }, @@ -104,3 +265,183 @@ func (sr *scrutinyRepository) Migrate(ctx context.Context) error { sr.logger.Infoln("Database migration completed successfully") return nil } + +// Deprecated +func m20201107210306_FromPreInfluxDBTempCreatePostInfluxDBTemp(preDevice m20201107210306.Device, preSmartResult m20201107210306.Smart) (error, measurements.SmartTemperature) { + //extract temperature data for every datapoint + postSmartTemp := measurements.SmartTemperature{ + Date: preSmartResult.TestDate, + Temp: preSmartResult.Temp, + } + + return nil, postSmartTemp +} + +// Deprecated +func m20201107210306_FromPreInfluxDBSmartResultsCreatePostInfluxDBSmartResults(database *gorm.DB, preDevice m20201107210306.Device, preSmartResult m20201107210306.Smart) (error, measurements.Smart) { + //create a measurements.Smart object (which we will then push to the InfluxDB) + postDeviceSmartData := measurements.Smart{ + Date: preSmartResult.TestDate, + DeviceWWN: preDevice.WWN, + DeviceProtocol: preDevice.DeviceProtocol, + Temp: preSmartResult.Temp, + PowerOnHours: preSmartResult.PowerOnHours, + PowerCycleCount: preSmartResult.PowerCycleCount, + + // this needs to be populated using measurements.Smart.ProcessAtaSmartInfo, ProcessScsiSmartInfo or ProcessNvmeSmartInfo + // because those functions will take into account thresholds (which we didn't consider correctly previously) + Attributes: map[string]measurements.SmartAttribute{}, + } + + result := database.Preload("AtaAttributes").Preload("NvmeAttributes").Preload("ScsiAttributes").Find(&preSmartResult) + if result.Error != nil { + return result.Error, postDeviceSmartData + } + + if preDevice.IsAta() { + preAtaSmartAttributesTable := []collector.AtaSmartAttributesTableItem{} + for _, preAtaAttribute := range preSmartResult.AtaAttributes { + preAtaSmartAttributesTable = append(preAtaSmartAttributesTable, collector.AtaSmartAttributesTableItem{ + ID: preAtaAttribute.AttributeId, + Name: preAtaAttribute.Name, + Value: int64(preAtaAttribute.Value), + Worst: int64(preAtaAttribute.Worst), + Thresh: int64(preAtaAttribute.Threshold), + WhenFailed: preAtaAttribute.WhenFailed, + Flags: struct { + Value int `json:"value"` + String string `json:"string"` + Prefailure bool `json:"prefailure"` + UpdatedOnline bool `json:"updated_online"` + Performance bool `json:"performance"` + ErrorRate bool `json:"error_rate"` + EventCount bool `json:"event_count"` + AutoKeep bool `json:"auto_keep"` + }{ + Value: 0, + String: "", + Prefailure: false, + UpdatedOnline: false, + Performance: false, + ErrorRate: false, + EventCount: false, + AutoKeep: false, + }, + Raw: struct { + Value int64 `json:"value"` + String string `json:"string"` + }{ + Value: preAtaAttribute.RawValue, + String: preAtaAttribute.RawString, + }, + }) + } + + postDeviceSmartData.ProcessAtaSmartInfo(preAtaSmartAttributesTable) + + } else if preDevice.IsNvme() { + //info collector.SmartInfo + postNvmeSmartHealthInformation := collector.NvmeSmartHealthInformationLog{} + + for _, preNvmeAttribute := range preSmartResult.NvmeAttributes { + switch preNvmeAttribute.AttributeId { + case "critical_warning": + postNvmeSmartHealthInformation.CriticalWarning = int64(preNvmeAttribute.Value) + case "temperature": + postNvmeSmartHealthInformation.Temperature = int64(preNvmeAttribute.Value) + case "available_spare": + postNvmeSmartHealthInformation.AvailableSpare = int64(preNvmeAttribute.Value) + case "available_spare_threshold": + postNvmeSmartHealthInformation.AvailableSpareThreshold = int64(preNvmeAttribute.Value) + case "percentage_used": + postNvmeSmartHealthInformation.PercentageUsed = int64(preNvmeAttribute.Value) + case "data_units_read": + postNvmeSmartHealthInformation.DataUnitsWritten = int64(preNvmeAttribute.Value) + case "data_units_written": + postNvmeSmartHealthInformation.DataUnitsWritten = int64(preNvmeAttribute.Value) + case "host_reads": + postNvmeSmartHealthInformation.HostReads = int64(preNvmeAttribute.Value) + case "host_writes": + postNvmeSmartHealthInformation.HostWrites = int64(preNvmeAttribute.Value) + case "controller_busy_time": + postNvmeSmartHealthInformation.ControllerBusyTime = int64(preNvmeAttribute.Value) + case "power_cycles": + postNvmeSmartHealthInformation.PowerCycles = int64(preNvmeAttribute.Value) + case "power_on_hours": + postNvmeSmartHealthInformation.PowerOnHours = int64(preNvmeAttribute.Value) + case "unsafe_shutdowns": + postNvmeSmartHealthInformation.UnsafeShutdowns = int64(preNvmeAttribute.Value) + case "media_errors": + postNvmeSmartHealthInformation.MediaErrors = int64(preNvmeAttribute.Value) + case "num_err_log_entries": + postNvmeSmartHealthInformation.NumErrLogEntries = int64(preNvmeAttribute.Value) + case "warning_temp_time": + postNvmeSmartHealthInformation.WarningTempTime = int64(preNvmeAttribute.Value) + case "critical_comp_time": + postNvmeSmartHealthInformation.CriticalCompTime = int64(preNvmeAttribute.Value) + } + } + + postDeviceSmartData.ProcessNvmeSmartInfo(postNvmeSmartHealthInformation) + + } else if preDevice.IsScsi() { + //info collector.SmartInfo + var postScsiGrownDefectList int64 + postScsiErrorCounterLog := collector.ScsiErrorCounterLog{ + Read: struct { + ErrorsCorrectedByEccfast int64 `json:"errors_corrected_by_eccfast"` + ErrorsCorrectedByEccdelayed int64 `json:"errors_corrected_by_eccdelayed"` + ErrorsCorrectedByRereadsRewrites int64 `json:"errors_corrected_by_rereads_rewrites"` + TotalErrorsCorrected int64 `json:"total_errors_corrected"` + CorrectionAlgorithmInvocations int64 `json:"correction_algorithm_invocations"` + GigabytesProcessed string `json:"gigabytes_processed"` + TotalUncorrectedErrors int64 `json:"total_uncorrected_errors"` + }{}, + Write: struct { + ErrorsCorrectedByEccfast int64 `json:"errors_corrected_by_eccfast"` + ErrorsCorrectedByEccdelayed int64 `json:"errors_corrected_by_eccdelayed"` + ErrorsCorrectedByRereadsRewrites int64 `json:"errors_corrected_by_rereads_rewrites"` + TotalErrorsCorrected int64 `json:"total_errors_corrected"` + CorrectionAlgorithmInvocations int64 `json:"correction_algorithm_invocations"` + GigabytesProcessed string `json:"gigabytes_processed"` + TotalUncorrectedErrors int64 `json:"total_uncorrected_errors"` + }{}, + } + + for _, preScsiAttribute := range preSmartResult.ScsiAttributes { + switch preScsiAttribute.AttributeId { + case "scsi_grown_defect_list": + postScsiGrownDefectList = int64(preScsiAttribute.Value) + case "read.errors_corrected_by_eccfast": + postScsiErrorCounterLog.Read.ErrorsCorrectedByEccfast = int64(preScsiAttribute.Value) + case "read.errors_corrected_by_eccdelayed": + postScsiErrorCounterLog.Read.ErrorsCorrectedByEccdelayed = int64(preScsiAttribute.Value) + case "read.errors_corrected_by_rereads_rewrites": + postScsiErrorCounterLog.Read.ErrorsCorrectedByRereadsRewrites = int64(preScsiAttribute.Value) + case "read.total_errors_corrected": + postScsiErrorCounterLog.Read.TotalErrorsCorrected = int64(preScsiAttribute.Value) + case "read.correction_algorithm_invocations": + postScsiErrorCounterLog.Read.CorrectionAlgorithmInvocations = int64(preScsiAttribute.Value) + case "read.total_uncorrected_errors": + postScsiErrorCounterLog.Read.TotalUncorrectedErrors = int64(preScsiAttribute.Value) + case "write.errors_corrected_by_eccfast": + postScsiErrorCounterLog.Write.ErrorsCorrectedByEccfast = int64(preScsiAttribute.Value) + case "write.errors_corrected_by_eccdelayed": + postScsiErrorCounterLog.Write.ErrorsCorrectedByEccdelayed = int64(preScsiAttribute.Value) + case "write.errors_corrected_by_rereads_rewrites": + postScsiErrorCounterLog.Write.ErrorsCorrectedByRereadsRewrites = int64(preScsiAttribute.Value) + case "write.total_errors_corrected": + postScsiErrorCounterLog.Write.TotalErrorsCorrected = int64(preScsiAttribute.Value) + case "write.correction_algorithm_invocations": + postScsiErrorCounterLog.Write.CorrectionAlgorithmInvocations = int64(preScsiAttribute.Value) + case "write.total_uncorrected_errors": + postScsiErrorCounterLog.Write.TotalUncorrectedErrors = int64(preScsiAttribute.Value) + } + } + postDeviceSmartData.ProcessScsiSmartInfo(postScsiGrownDefectList, postScsiErrorCounterLog) + } else { + return fmt.Errorf("Unknown device protocol: %s", preDevice.DeviceProtocol), postDeviceSmartData + } + + return nil, postDeviceSmartData +} diff --git a/webapp/backend/pkg/models/collector/smart.go b/webapp/backend/pkg/models/collector/smart.go index 8cb5653..4f7ae3d 100644 --- a/webapp/backend/pkg/models/collector/smart.go +++ b/webapp/backend/pkg/models/collector/smart.go @@ -134,29 +134,8 @@ type SmartInfo struct { Table []int64 `json:"table"` } `json:"ata_sct_temperature_history"` AtaSmartAttributes struct { - Revision int `json:"revision"` - Table []struct { - ID int `json:"id"` - Name string `json:"name"` - Value int64 `json:"value"` - Worst int64 `json:"worst"` - Thresh int64 `json:"thresh"` - WhenFailed string `json:"when_failed"` - Flags struct { - Value int `json:"value"` - String string `json:"string"` - Prefailure bool `json:"prefailure"` - UpdatedOnline bool `json:"updated_online"` - Performance bool `json:"performance"` - ErrorRate bool `json:"error_rate"` - EventCount bool `json:"event_count"` - AutoKeep bool `json:"auto_keep"` - } `json:"flags"` - Raw struct { - Value int64 `json:"value"` - String string `json:"string"` - } `json:"raw"` - } `json:"table"` + Revision int `json:"revision"` + Table []AtaSmartAttributesTableItem `json:"table"` } `json:"ata_smart_attributes"` AtaSmartErrorLog struct { Summary struct { @@ -250,49 +229,77 @@ type SmartInfo struct { } `json:"utilization"` FormattedLbaSize int `json:"formatted_lba_size"` } `json:"nvme_namespaces"` - NvmeSmartHealthInformationLog struct { - CriticalWarning int64 `json:"critical_warning"` - Temperature int64 `json:"temperature"` - AvailableSpare int64 `json:"available_spare"` - AvailableSpareThreshold int64 `json:"available_spare_threshold"` - PercentageUsed int64 `json:"percentage_used"` - DataUnitsRead int64 `json:"data_units_read"` - DataUnitsWritten int64 `json:"data_units_written"` - HostReads int64 `json:"host_reads"` - HostWrites int64 `json:"host_writes"` - ControllerBusyTime int64 `json:"controller_busy_time"` - PowerCycles int64 `json:"power_cycles"` - PowerOnHours int64 `json:"power_on_hours"` - UnsafeShutdowns int64 `json:"unsafe_shutdowns"` - MediaErrors int64 `json:"media_errors"` - NumErrLogEntries int64 `json:"num_err_log_entries"` - WarningTempTime int64 `json:"warning_temp_time"` - CriticalCompTime int64 `json:"critical_comp_time"` - } `json:"nvme_smart_health_information_log"` + NvmeSmartHealthInformationLog NvmeSmartHealthInformationLog `json:"nvme_smart_health_information_log"` // SCSI Protocol Specific Fields - Vendor string `json:"vendor"` - Product string `json:"product"` - ScsiVersion string `json:"scsi_version"` - ScsiGrownDefectList int64 `json:"scsi_grown_defect_list"` - ScsiErrorCounterLog struct { - Read struct { - ErrorsCorrectedByEccfast int64 `json:"errors_corrected_by_eccfast"` - ErrorsCorrectedByEccdelayed int64 `json:"errors_corrected_by_eccdelayed"` - ErrorsCorrectedByRereadsRewrites int64 `json:"errors_corrected_by_rereads_rewrites"` - TotalErrorsCorrected int64 `json:"total_errors_corrected"` - CorrectionAlgorithmInvocations int64 `json:"correction_algorithm_invocations"` - GigabytesProcessed string `json:"gigabytes_processed"` - TotalUncorrectedErrors int64 `json:"total_uncorrected_errors"` - } `json:"read"` - Write struct { - ErrorsCorrectedByEccfast int64 `json:"errors_corrected_by_eccfast"` - ErrorsCorrectedByEccdelayed int64 `json:"errors_corrected_by_eccdelayed"` - ErrorsCorrectedByRereadsRewrites int64 `json:"errors_corrected_by_rereads_rewrites"` - TotalErrorsCorrected int64 `json:"total_errors_corrected"` - CorrectionAlgorithmInvocations int64 `json:"correction_algorithm_invocations"` - GigabytesProcessed string `json:"gigabytes_processed"` - TotalUncorrectedErrors int64 `json:"total_uncorrected_errors"` - } `json:"write"` - } `json:"scsi_error_counter_log"` + Vendor string `json:"vendor"` + Product string `json:"product"` + ScsiVersion string `json:"scsi_version"` + ScsiGrownDefectList int64 `json:"scsi_grown_defect_list"` + ScsiErrorCounterLog ScsiErrorCounterLog `json:"scsi_error_counter_log"` +} + +//Primary Attribute Structs +type AtaSmartAttributesTableItem struct { + ID int `json:"id"` + Name string `json:"name"` + Value int64 `json:"value"` + Worst int64 `json:"worst"` + Thresh int64 `json:"thresh"` + WhenFailed string `json:"when_failed"` + Flags struct { + Value int `json:"value"` + String string `json:"string"` + Prefailure bool `json:"prefailure"` + UpdatedOnline bool `json:"updated_online"` + Performance bool `json:"performance"` + ErrorRate bool `json:"error_rate"` + EventCount bool `json:"event_count"` + AutoKeep bool `json:"auto_keep"` + } `json:"flags"` + Raw struct { + Value int64 `json:"value"` + String string `json:"string"` + } `json:"raw"` +} + +type NvmeSmartHealthInformationLog struct { + CriticalWarning int64 `json:"critical_warning"` + Temperature int64 `json:"temperature"` + AvailableSpare int64 `json:"available_spare"` + AvailableSpareThreshold int64 `json:"available_spare_threshold"` + PercentageUsed int64 `json:"percentage_used"` + DataUnitsRead int64 `json:"data_units_read"` + DataUnitsWritten int64 `json:"data_units_written"` + HostReads int64 `json:"host_reads"` + HostWrites int64 `json:"host_writes"` + ControllerBusyTime int64 `json:"controller_busy_time"` + PowerCycles int64 `json:"power_cycles"` + PowerOnHours int64 `json:"power_on_hours"` + UnsafeShutdowns int64 `json:"unsafe_shutdowns"` + MediaErrors int64 `json:"media_errors"` + NumErrLogEntries int64 `json:"num_err_log_entries"` + WarningTempTime int64 `json:"warning_temp_time"` + CriticalCompTime int64 `json:"critical_comp_time"` +} + +type ScsiErrorCounterLog struct { + Read struct { + ErrorsCorrectedByEccfast int64 `json:"errors_corrected_by_eccfast"` + ErrorsCorrectedByEccdelayed int64 `json:"errors_corrected_by_eccdelayed"` + ErrorsCorrectedByRereadsRewrites int64 `json:"errors_corrected_by_rereads_rewrites"` + TotalErrorsCorrected int64 `json:"total_errors_corrected"` + CorrectionAlgorithmInvocations int64 `json:"correction_algorithm_invocations"` + GigabytesProcessed string `json:"gigabytes_processed"` + TotalUncorrectedErrors int64 `json:"total_uncorrected_errors"` + } `json:"read"` + Write struct { + ErrorsCorrectedByEccfast int64 `json:"errors_corrected_by_eccfast"` + ErrorsCorrectedByEccdelayed int64 `json:"errors_corrected_by_eccdelayed"` + ErrorsCorrectedByRereadsRewrites int64 `json:"errors_corrected_by_rereads_rewrites"` + TotalErrorsCorrected int64 `json:"total_errors_corrected"` + CorrectionAlgorithmInvocations int64 `json:"correction_algorithm_invocations"` + GigabytesProcessed string `json:"gigabytes_processed"` + TotalUncorrectedErrors int64 `json:"total_uncorrected_errors"` + } `json:"write"` } diff --git a/webapp/backend/pkg/models/measurements/smart.go b/webapp/backend/pkg/models/measurements/smart.go index 37810f4..cc25593 100644 --- a/webapp/backend/pkg/models/measurements/smart.go +++ b/webapp/backend/pkg/models/measurements/smart.go @@ -125,20 +125,20 @@ func (sm *Smart) FromCollectorSmartInfo(wwn string, info collector.SmartInfo) er // process ATA/NVME/SCSI protocol data sm.Attributes = map[string]SmartAttribute{} if sm.DeviceProtocol == pkg.DeviceProtocolAta { - sm.ProcessAtaSmartInfo(info) + sm.ProcessAtaSmartInfo(info.AtaSmartAttributes.Table) } else if sm.DeviceProtocol == pkg.DeviceProtocolNvme { - sm.ProcessNvmeSmartInfo(info) + sm.ProcessNvmeSmartInfo(info.NvmeSmartHealthInformationLog) } else if sm.DeviceProtocol == pkg.DeviceProtocolScsi { - sm.ProcessScsiSmartInfo(info) + sm.ProcessScsiSmartInfo(info.ScsiGrownDefectList, info.ScsiErrorCounterLog) } return nil } //generate SmartAtaAttribute entries from Scrutiny Collector Smart data. -func (sm *Smart) ProcessAtaSmartInfo(info collector.SmartInfo) { +func (sm *Smart) ProcessAtaSmartInfo(tableItems []collector.AtaSmartAttributesTableItem) { sm.Status = pkg.DeviceStatusPassed - for _, collectorAttr := range info.AtaSmartAttributes.Table { + for _, collectorAttr := range tableItems { attrModel := SmartAtaAttribute{ AttributeId: collectorAttr.ID, Value: collectorAttr.Value, @@ -164,25 +164,25 @@ func (sm *Smart) ProcessAtaSmartInfo(info collector.SmartInfo) { } //generate SmartNvmeAttribute entries from Scrutiny Collector Smart data. -func (sm *Smart) ProcessNvmeSmartInfo(info collector.SmartInfo) { +func (sm *Smart) ProcessNvmeSmartInfo(nvmeSmartHealthInformationLog collector.NvmeSmartHealthInformationLog) { sm.Attributes = map[string]SmartAttribute{ - "critical_warning": (&SmartNvmeAttribute{AttributeId: "critical_warning", Value: info.NvmeSmartHealthInformationLog.CriticalWarning, Threshold: 0}).PopulateAttributeStatus(), - "temperature": (&SmartNvmeAttribute{AttributeId: "temperature", Value: info.NvmeSmartHealthInformationLog.Temperature, Threshold: -1}).PopulateAttributeStatus(), - "available_spare": (&SmartNvmeAttribute{AttributeId: "available_spare", Value: info.NvmeSmartHealthInformationLog.AvailableSpare, Threshold: info.NvmeSmartHealthInformationLog.AvailableSpareThreshold}).PopulateAttributeStatus(), - "percentage_used": (&SmartNvmeAttribute{AttributeId: "percentage_used", Value: info.NvmeSmartHealthInformationLog.PercentageUsed, Threshold: 100}).PopulateAttributeStatus(), - "data_units_read": (&SmartNvmeAttribute{AttributeId: "data_units_read", Value: info.NvmeSmartHealthInformationLog.DataUnitsRead, Threshold: -1}).PopulateAttributeStatus(), - "data_units_written": (&SmartNvmeAttribute{AttributeId: "data_units_written", Value: info.NvmeSmartHealthInformationLog.DataUnitsWritten, Threshold: -1}).PopulateAttributeStatus(), - "host_reads": (&SmartNvmeAttribute{AttributeId: "host_reads", Value: info.NvmeSmartHealthInformationLog.HostReads, Threshold: -1}).PopulateAttributeStatus(), - "host_writes": (&SmartNvmeAttribute{AttributeId: "host_writes", Value: info.NvmeSmartHealthInformationLog.HostWrites, Threshold: -1}).PopulateAttributeStatus(), - "controller_busy_time": (&SmartNvmeAttribute{AttributeId: "controller_busy_time", Value: info.NvmeSmartHealthInformationLog.ControllerBusyTime, Threshold: -1}).PopulateAttributeStatus(), - "power_cycles": (&SmartNvmeAttribute{AttributeId: "power_cycles", Value: info.NvmeSmartHealthInformationLog.PowerCycles, Threshold: -1}).PopulateAttributeStatus(), - "power_on_hours": (&SmartNvmeAttribute{AttributeId: "power_on_hours", Value: info.NvmeSmartHealthInformationLog.PowerOnHours, Threshold: -1}).PopulateAttributeStatus(), - "unsafe_shutdowns": (&SmartNvmeAttribute{AttributeId: "unsafe_shutdowns", Value: info.NvmeSmartHealthInformationLog.UnsafeShutdowns, Threshold: -1}).PopulateAttributeStatus(), - "media_errors": (&SmartNvmeAttribute{AttributeId: "media_errors", Value: info.NvmeSmartHealthInformationLog.MediaErrors, Threshold: 0}).PopulateAttributeStatus(), - "num_err_log_entries": (&SmartNvmeAttribute{AttributeId: "num_err_log_entries", Value: info.NvmeSmartHealthInformationLog.NumErrLogEntries, Threshold: 0}).PopulateAttributeStatus(), - "warning_temp_time": (&SmartNvmeAttribute{AttributeId: "warning_temp_time", Value: info.NvmeSmartHealthInformationLog.WarningTempTime, Threshold: -1}).PopulateAttributeStatus(), - "critical_comp_time": (&SmartNvmeAttribute{AttributeId: "critical_comp_time", Value: info.NvmeSmartHealthInformationLog.CriticalCompTime, Threshold: -1}).PopulateAttributeStatus(), + "critical_warning": (&SmartNvmeAttribute{AttributeId: "critical_warning", Value: nvmeSmartHealthInformationLog.CriticalWarning, Threshold: 0}).PopulateAttributeStatus(), + "temperature": (&SmartNvmeAttribute{AttributeId: "temperature", Value: nvmeSmartHealthInformationLog.Temperature, Threshold: -1}).PopulateAttributeStatus(), + "available_spare": (&SmartNvmeAttribute{AttributeId: "available_spare", Value: nvmeSmartHealthInformationLog.AvailableSpare, Threshold: nvmeSmartHealthInformationLog.AvailableSpareThreshold}).PopulateAttributeStatus(), + "percentage_used": (&SmartNvmeAttribute{AttributeId: "percentage_used", Value: nvmeSmartHealthInformationLog.PercentageUsed, Threshold: 100}).PopulateAttributeStatus(), + "data_units_read": (&SmartNvmeAttribute{AttributeId: "data_units_read", Value: nvmeSmartHealthInformationLog.DataUnitsRead, Threshold: -1}).PopulateAttributeStatus(), + "data_units_written": (&SmartNvmeAttribute{AttributeId: "data_units_written", Value: nvmeSmartHealthInformationLog.DataUnitsWritten, Threshold: -1}).PopulateAttributeStatus(), + "host_reads": (&SmartNvmeAttribute{AttributeId: "host_reads", Value: nvmeSmartHealthInformationLog.HostReads, Threshold: -1}).PopulateAttributeStatus(), + "host_writes": (&SmartNvmeAttribute{AttributeId: "host_writes", Value: nvmeSmartHealthInformationLog.HostWrites, Threshold: -1}).PopulateAttributeStatus(), + "controller_busy_time": (&SmartNvmeAttribute{AttributeId: "controller_busy_time", Value: nvmeSmartHealthInformationLog.ControllerBusyTime, Threshold: -1}).PopulateAttributeStatus(), + "power_cycles": (&SmartNvmeAttribute{AttributeId: "power_cycles", Value: nvmeSmartHealthInformationLog.PowerCycles, Threshold: -1}).PopulateAttributeStatus(), + "power_on_hours": (&SmartNvmeAttribute{AttributeId: "power_on_hours", Value: nvmeSmartHealthInformationLog.PowerOnHours, Threshold: -1}).PopulateAttributeStatus(), + "unsafe_shutdowns": (&SmartNvmeAttribute{AttributeId: "unsafe_shutdowns", Value: nvmeSmartHealthInformationLog.UnsafeShutdowns, Threshold: -1}).PopulateAttributeStatus(), + "media_errors": (&SmartNvmeAttribute{AttributeId: "media_errors", Value: nvmeSmartHealthInformationLog.MediaErrors, Threshold: 0}).PopulateAttributeStatus(), + "num_err_log_entries": (&SmartNvmeAttribute{AttributeId: "num_err_log_entries", Value: nvmeSmartHealthInformationLog.NumErrLogEntries, Threshold: 0}).PopulateAttributeStatus(), + "warning_temp_time": (&SmartNvmeAttribute{AttributeId: "warning_temp_time", Value: nvmeSmartHealthInformationLog.WarningTempTime, Threshold: -1}).PopulateAttributeStatus(), + "critical_comp_time": (&SmartNvmeAttribute{AttributeId: "critical_comp_time", Value: nvmeSmartHealthInformationLog.CriticalCompTime, Threshold: -1}).PopulateAttributeStatus(), } //find analyzed attribute status @@ -194,21 +194,21 @@ func (sm *Smart) ProcessNvmeSmartInfo(info collector.SmartInfo) { } //generate SmartScsiAttribute entries from Scrutiny Collector Smart data. -func (sm *Smart) ProcessScsiSmartInfo(info collector.SmartInfo) { +func (sm *Smart) ProcessScsiSmartInfo(defectGrownList int64, scsiErrorCounterLog collector.ScsiErrorCounterLog) { sm.Attributes = map[string]SmartAttribute{ - "scsi_grown_defect_list": (&SmartScsiAttribute{AttributeId: "scsi_grown_defect_list", Value: info.ScsiGrownDefectList, Threshold: 0}).PopulateAttributeStatus(), - "read_errors_corrected_by_eccfast": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccfast", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccfast, Threshold: -1}).PopulateAttributeStatus(), - "read_errors_corrected_by_eccdelayed": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccdelayed", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccdelayed, Threshold: -1}).PopulateAttributeStatus(), - "read_errors_corrected_by_rereads_rewrites": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_rereads_rewrites", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByRereadsRewrites, Threshold: 0}).PopulateAttributeStatus(), - "read_total_errors_corrected": (&SmartScsiAttribute{AttributeId: "read_total_errors_corrected", Value: info.ScsiErrorCounterLog.Read.TotalErrorsCorrected, Threshold: -1}).PopulateAttributeStatus(), - "read_correction_algorithm_invocations": (&SmartScsiAttribute{AttributeId: "read_correction_algorithm_invocations", Value: info.ScsiErrorCounterLog.Read.CorrectionAlgorithmInvocations, Threshold: -1}).PopulateAttributeStatus(), - "read_total_uncorrected_errors": (&SmartScsiAttribute{AttributeId: "read_total_uncorrected_errors", Value: info.ScsiErrorCounterLog.Read.TotalUncorrectedErrors, Threshold: 0}).PopulateAttributeStatus(), - "write_errors_corrected_by_eccfast": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccfast", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccfast, Threshold: -1}).PopulateAttributeStatus(), - "write_errors_corrected_by_eccdelayed": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccdelayed", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccdelayed, Threshold: -1}).PopulateAttributeStatus(), - "write_errors_corrected_by_rereads_rewrites": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_rereads_rewrites", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByRereadsRewrites, Threshold: 0}).PopulateAttributeStatus(), - "write_total_errors_corrected": (&SmartScsiAttribute{AttributeId: "write_total_errors_corrected", Value: info.ScsiErrorCounterLog.Write.TotalErrorsCorrected, Threshold: -1}).PopulateAttributeStatus(), - "write_correction_algorithm_invocations": (&SmartScsiAttribute{AttributeId: "write_correction_algorithm_invocations", Value: info.ScsiErrorCounterLog.Write.CorrectionAlgorithmInvocations, Threshold: -1}).PopulateAttributeStatus(), - "write_total_uncorrected_errors": (&SmartScsiAttribute{AttributeId: "write_total_uncorrected_errors", Value: info.ScsiErrorCounterLog.Write.TotalUncorrectedErrors, Threshold: 0}).PopulateAttributeStatus(), + "scsi_grown_defect_list": (&SmartScsiAttribute{AttributeId: "scsi_grown_defect_list", Value: defectGrownList, Threshold: 0}).PopulateAttributeStatus(), + "read_errors_corrected_by_eccfast": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccfast", Value: scsiErrorCounterLog.Read.ErrorsCorrectedByEccfast, Threshold: -1}).PopulateAttributeStatus(), + "read_errors_corrected_by_eccdelayed": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccdelayed", Value: scsiErrorCounterLog.Read.ErrorsCorrectedByEccdelayed, Threshold: -1}).PopulateAttributeStatus(), + "read_errors_corrected_by_rereads_rewrites": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_rereads_rewrites", Value: scsiErrorCounterLog.Read.ErrorsCorrectedByRereadsRewrites, Threshold: 0}).PopulateAttributeStatus(), + "read_total_errors_corrected": (&SmartScsiAttribute{AttributeId: "read_total_errors_corrected", Value: scsiErrorCounterLog.Read.TotalErrorsCorrected, Threshold: -1}).PopulateAttributeStatus(), + "read_correction_algorithm_invocations": (&SmartScsiAttribute{AttributeId: "read_correction_algorithm_invocations", Value: scsiErrorCounterLog.Read.CorrectionAlgorithmInvocations, Threshold: -1}).PopulateAttributeStatus(), + "read_total_uncorrected_errors": (&SmartScsiAttribute{AttributeId: "read_total_uncorrected_errors", Value: scsiErrorCounterLog.Read.TotalUncorrectedErrors, Threshold: 0}).PopulateAttributeStatus(), + "write_errors_corrected_by_eccfast": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccfast", Value: scsiErrorCounterLog.Write.ErrorsCorrectedByEccfast, Threshold: -1}).PopulateAttributeStatus(), + "write_errors_corrected_by_eccdelayed": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccdelayed", Value: scsiErrorCounterLog.Write.ErrorsCorrectedByEccdelayed, Threshold: -1}).PopulateAttributeStatus(), + "write_errors_corrected_by_rereads_rewrites": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_rereads_rewrites", Value: scsiErrorCounterLog.Write.ErrorsCorrectedByRereadsRewrites, Threshold: 0}).PopulateAttributeStatus(), + "write_total_errors_corrected": (&SmartScsiAttribute{AttributeId: "write_total_errors_corrected", Value: scsiErrorCounterLog.Write.TotalErrorsCorrected, Threshold: -1}).PopulateAttributeStatus(), + "write_correction_algorithm_invocations": (&SmartScsiAttribute{AttributeId: "write_correction_algorithm_invocations", Value: scsiErrorCounterLog.Write.CorrectionAlgorithmInvocations, Threshold: -1}).PopulateAttributeStatus(), + "write_total_uncorrected_errors": (&SmartScsiAttribute{AttributeId: "write_total_uncorrected_errors", Value: scsiErrorCounterLog.Write.TotalUncorrectedErrors, Threshold: 0}).PopulateAttributeStatus(), } //find analyzed attribute status From fc5a9ba15e15e3e593975eb273f2dcff830c43bb Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Wed, 4 May 2022 20:13:11 -0700 Subject: [PATCH 086/114] fixed device processing in details page. Summary query is still broken. --- .../backend/pkg/database/scrutiny_repository.go | 2 +- ...scrutiny_repository_device_smart_attributes.go | 2 +- .../database/scrutiny_repository_migrations.go | 15 ++++++++++----- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index 41b89aa..a285091 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -368,7 +368,7 @@ func (sr *scrutinyRepository) lookupNestedDurationKeys(durationKey string) []str return []string{DURATION_KEY_WEEK, DURATION_KEY_MONTH, DURATION_KEY_YEAR} case DURATION_KEY_FOREVER: //data stored before the last year - return []string{DURATION_KEY_WEEK, DURATION_KEY_MONTH, DURATION_KEY_YEAR} + return []string{DURATION_KEY_WEEK, DURATION_KEY_MONTH, DURATION_KEY_YEAR, DURATION_KEY_FOREVER} } return []string{DURATION_KEY_WEEK} } diff --git a/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go b/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go index 19d5861..eaa1852 100644 --- a/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go +++ b/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go @@ -92,7 +92,7 @@ func (sr *scrutinyRepository) GetSmartAttributeHistory(ctx context.Context, wwn //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// func (sr *scrutinyRepository) saveDatapoint(influxWriteApi api.WriteAPIBlocking, measurement string, tags map[string]string, fields map[string]interface{}, date time.Time, ctx context.Context) error { - sr.logger.Debugf("Storing datapoint in measurement '%s'. tags: %d fields: %d", measurement, len(tags), len(fields)) + //sr.logger.Debugf("Storing datapoint in measurement '%s'. tags: %d fields: %d", measurement, len(tags), len(fields)) p := influxdb2.NewPoint(measurement, tags, fields, diff --git a/webapp/backend/pkg/database/scrutiny_repository_migrations.go b/webapp/backend/pkg/database/scrutiny_repository_migrations.go index 0c12186..5f6496a 100644 --- a/webapp/backend/pkg/database/scrutiny_repository_migrations.go +++ b/webapp/backend/pkg/database/scrutiny_repository_migrations.go @@ -88,11 +88,6 @@ func (sr *scrutinyRepository) Migrate(ctx context.Context) error { return err } - //weekly, monthly, yearly lookup storage, so we don't add more data to the buckets than necessary. - weeklyLookup := map[string]bool{} - monthlyLookup := map[string]bool{} - yearlyLookup := map[string]bool{} - //calculate bucket oldest dates today := time.Now() dailyBucketMax := today.Add(-RETENTION_PERIOD_15_DAYS_IN_SECONDS * time.Second) //15 days @@ -100,6 +95,12 @@ func (sr *scrutinyRepository) Migrate(ctx context.Context) error { monthlyBucketMax := today.Add(-RETENTION_PERIOD_25_MONTHS_IN_SECONDS * time.Second) //25 weeks for _, preDevice := range preDevices { + sr.logger.Infof("\n====================================\n\nBegin processing device %s\n\n====================================\n", preDevice.WWN) + + //weekly, monthly, yearly lookup storage, so we don't add more data to the buckets than necessary. + weeklyLookup := map[string]bool{} + monthlyLookup := map[string]bool{} + yearlyLookup := map[string]bool{} for _, preSmartResult := range preDevice.SmartResults { //pre-migration smart results //we're looping in ASC mode, so from oldest entry to most current. @@ -183,6 +184,7 @@ func (sr *scrutinyRepository) Migrate(ctx context.Context) error { //write data to the monthly bucket if in the last 9 weeks, and week has not been processed yet if _, monthExists := monthlyLookup[yearMonthStr]; !monthExists && postSmartResults.Date.After(monthlyBucketMax) { sr.logger.Debugf("device (%s) smart data added to bucket: monthly", preDevice.WWN) + //this month/year pair has not been processed monthlyLookup[yearMonthStr] = true // write point immediately @@ -209,6 +211,7 @@ func (sr *scrutinyRepository) Migrate(ctx context.Context) error { if _, yearExists := yearlyLookup[yearStr]; !yearExists && year != today.Year() { sr.logger.Debugf("device (%s) smart data added to bucket: yearly", preDevice.WWN) + //this year has not been processed yearlyLookup[yearStr] = true // write point immediately @@ -233,6 +236,8 @@ func (sr *scrutinyRepository) Migrate(ctx context.Context) error { } } } + fmt.Printf("finished processing device %s. weekly: %d, monthly: %d, yearly: %d", preDevice.WWN, len(weeklyLookup), len(monthlyLookup), len(yearlyLookup)) + } return nil From 702518579b98c5f00cad985100f098304149d608 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Wed, 4 May 2022 20:40:48 -0700 Subject: [PATCH 087/114] fixed summary query. --- .../pkg/database/scrutiny_repository.go | 49 +++++++++++++++---- ...tiny_repository_device_smart_attributes.go | 41 +++++++++------- 2 files changed, 64 insertions(+), 26 deletions(-) diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index a285091..c35923f 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -252,15 +252,46 @@ func (sr *scrutinyRepository) GetSummary(ctx context.Context) (map[string]*model // Get parser flux query result //appConfig.GetString("web.influxdb.bucket") queryStr := fmt.Sprintf(` - import "influxdata/influxdb/schema" - from(bucket: "%s") - |> range(start: -1y, stop: now()) - |> filter(fn: (r) => r["_measurement"] == "smart" ) - |> filter(fn: (r) => r["_field"] == "temp" or r["_field"] == "power_on_hours" or r["_field"] == "date") - |> last() - |> schema.fieldsAsCols() - |> group(columns: ["device_wwn"]) - |> yield(name: "last") + import "influxdata/influxdb/schema" + bucketBaseName = "%s" + + dailyData = from(bucket: bucketBaseName) + |> range(start: -10y, stop: now()) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> filter(fn: (r) => r["_field"] == "temp" or r["_field"] == "power_on_hours" or r["_field"] == "date") + |> last() + |> schema.fieldsAsCols() + |> group(columns: ["device_wwn"]) + + weeklyData = from(bucket: bucketBaseName + "_weekly") + |> range(start: -10y, stop: now()) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> filter(fn: (r) => r["_field"] == "temp" or r["_field"] == "power_on_hours" or r["_field"] == "date") + |> last() + |> schema.fieldsAsCols() + |> group(columns: ["device_wwn"]) + + monthlyData = from(bucket: bucketBaseName + "_monthly") + |> range(start: -10y, stop: now()) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> filter(fn: (r) => r["_field"] == "temp" or r["_field"] == "power_on_hours" or r["_field"] == "date") + |> last() + |> schema.fieldsAsCols() + |> group(columns: ["device_wwn"]) + + yearlyData = from(bucket: bucketBaseName + "_yearly") + |> range(start: -10y, stop: now()) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> filter(fn: (r) => r["_field"] == "temp" or r["_field"] == "power_on_hours" or r["_field"] == "date") + |> last() + |> schema.fieldsAsCols() + |> group(columns: ["device_wwn"]) + + union(tables: [dailyData, weeklyData, monthlyData, yearlyData]) + |> sort(columns: ["_time"], desc: false) + |> group(columns: ["device_wwn"]) + |> last(column: "device_wwn") + |> yield(name: "last") `, sr.appConfig.GetString("web.influxdb.bucket"), ) diff --git a/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go b/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go index eaa1852..0479986 100644 --- a/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go +++ b/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go @@ -108,25 +108,32 @@ func (sr *scrutinyRepository) aggregateSmartAttributesQuery(wwn string, duration import "influxdata/influxdb/schema" weekData = from(bucket: "metrics") - |> range(start: -1w, stop: now()) - |> filter(fn: (r) => r["_measurement"] == "smart" ) - |> filter(fn: (r) => r["device_wwn"] == "%s" ) - |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) - |> group(columns: ["device_wwn"]) - |> toInt() + |> range(start: -1w, stop: now()) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> filter(fn: (r) => r["device_wwn"] == "0x5000c5002df89099" ) + |> schema.fieldsAsCols() monthData = from(bucket: "metrics_weekly") - |> range(start: -1mo, stop: now()) - |> filter(fn: (r) => r["_measurement"] == "smart" ) - |> filter(fn: (r) => r["device_wwn"] == "%s" ) - |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) - |> group(columns: ["device_wwn"]) - |> toInt() - - union(tables: [weekData, monthData]) - |> group(columns: ["device_wwn"]) - |> sort(columns: ["_time"], desc: false) - |> schema.fieldsAsCols() + |> range(start: -1mo, stop: -1w) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> filter(fn: (r) => r["device_wwn"] == "0x5000c5002df89099" ) + |> schema.fieldsAsCols() + + yearData = from(bucket: "metrics_monthly") + |> range(start: -1y, stop: -1mo) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> filter(fn: (r) => r["device_wwn"] == "0x5000c5002df89099" ) + |> schema.fieldsAsCols() + + foreverData = from(bucket: "metrics_yearly") + |> range(start: -10y, stop: -1y) + |> filter(fn: (r) => r["_measurement"] == "smart" ) + |> filter(fn: (r) => r["device_wwn"] == "0x5000c5002df89099" ) + |> schema.fieldsAsCols() + + union(tables: [weekData, monthData, yearData, foreverData]) + |> sort(columns: ["_time"], desc: false) + |> yield(name: "last") */ From 5f12fbb51095ddd5ce507335a7c514f5b3665e9b Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Wed, 4 May 2022 20:50:17 -0700 Subject: [PATCH 088/114] enable final migration cleanup. --- .../scrutiny_repository_migrations.go | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/webapp/backend/pkg/database/scrutiny_repository_migrations.go b/webapp/backend/pkg/database/scrutiny_repository_migrations.go index 5f6496a..f431145 100644 --- a/webapp/backend/pkg/database/scrutiny_repository_migrations.go +++ b/webapp/backend/pkg/database/scrutiny_repository_migrations.go @@ -95,7 +95,8 @@ func (sr *scrutinyRepository) Migrate(ctx context.Context) error { monthlyBucketMax := today.Add(-RETENTION_PERIOD_25_MONTHS_IN_SECONDS * time.Second) //25 weeks for _, preDevice := range preDevices { - sr.logger.Infof("\n====================================\n\nBegin processing device %s\n\n====================================\n", preDevice.WWN) + sr.logger.Debugf("====================================") + sr.logger.Infof("begin processing device: %s", preDevice.WWN) //weekly, monthly, yearly lookup storage, so we don't add more data to the buckets than necessary. weeklyLookup := map[string]bool{} @@ -105,8 +106,6 @@ func (sr *scrutinyRepository) Migrate(ctx context.Context) error { //we're looping in ASC mode, so from oldest entry to most current. - //TODO: skip any results that are outside of the range that we care about for each bucket. - err, postSmartResults := m20201107210306_FromPreInfluxDBSmartResultsCreatePostInfluxDBSmartResults(tx, preDevice, preSmartResult) if err != nil { return err @@ -236,31 +235,31 @@ func (sr *scrutinyRepository) Migrate(ctx context.Context) error { } } } - fmt.Printf("finished processing device %s. weekly: %d, monthly: %d, yearly: %d", preDevice.WWN, len(weeklyLookup), len(monthlyLookup), len(yearlyLookup)) + sr.logger.Infof("finished processing device %s. weekly: %d, monthly: %d, yearly: %d", preDevice.WWN, len(weeklyLookup), len(monthlyLookup), len(yearlyLookup)) } return nil }, }, - //{ - // ID: "20220503120000", // cleanup - v0.4.0 - influxdb schema - // Migrate: func(tx *gorm.DB) error { - // // delete unnecessary tables. - // err := tx.Migrator().DropTable( - // &m20201107210306.Smart{}, - // &m20201107210306.SmartAtaAttribute{}, - // &m20201107210306.SmartNvmeAttribute{}, - // &m20201107210306.SmartNvmeAttribute{}, - // ) - // if err != nil { - // return err - // } - // - // //migrate the device database to the final version - // return tx.AutoMigrate(models.Device{}) - // }, - //}, + { + ID: "20220503120000", // cleanup - v0.4.0 - influxdb schema + Migrate: func(tx *gorm.DB) error { + // delete unnecessary tables. + err := tx.Migrator().DropTable( + &m20201107210306.Smart{}, + &m20201107210306.SmartAtaAttribute{}, + &m20201107210306.SmartNvmeAttribute{}, + &m20201107210306.SmartScsiAttribute{}, + ) + if err != nil { + return err + } + + //migrate the device database to the final version + return tx.AutoMigrate(models.Device{}) + }, + }, }) if err := m.Migrate(); err != nil { From 1ced2198c7044061c96bf89413ee5e5343aac5f4 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Wed, 4 May 2022 21:04:58 -0700 Subject: [PATCH 089/114] cleanup log messages. --- .../scrutiny_repository_device_smart_attributes.go | 7 ------- webapp/backend/pkg/models/measurements/smart.go | 13 +------------ 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go b/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go index 0479986..18960cb 100644 --- a/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go +++ b/webapp/backend/pkg/database/scrutiny_repository_device_smart_attributes.go @@ -32,8 +32,6 @@ func (sr *scrutinyRepository) SaveSmartAttributes(ctx context.Context, wwn strin func (sr *scrutinyRepository) GetSmartAttributeHistory(ctx context.Context, wwn string, durationKey string, attributes []string) ([]measurements.Smart, error) { // Get SMartResults from InfluxDB - fmt.Println("GetDeviceDetails from INFLUXDB") - //TODO: change the filter startrange to a real number. // Get parser flux query result @@ -45,18 +43,13 @@ func (sr *scrutinyRepository) GetSmartAttributeHistory(ctx context.Context, wwn result, err := sr.influxQueryApi.Query(ctx, queryStr) if err == nil { - fmt.Println("GetDeviceDetails NO EROR") - // Use Next() to iterate over query result lines for result.Next() { - fmt.Println("GetDeviceDetails NEXT") - // Observe when there is new grouping key producing new table if result.TableChanged() { //fmt.Printf("table: %s\n", result.TableMetadata().String()) } - fmt.Printf("DECODINIG TABLE VALUES: %v", result.Record().Values()) smartData, err := measurements.NewSmartFromInfluxDB(result.Record().Values()) if err != nil { return nil, err diff --git a/webapp/backend/pkg/models/measurements/smart.go b/webapp/backend/pkg/models/measurements/smart.go index cc25593..c0523b1 100644 --- a/webapp/backend/pkg/models/measurements/smart.go +++ b/webapp/backend/pkg/models/measurements/smart.go @@ -61,12 +61,7 @@ func NewSmartFromInfluxDB(attrs map[string]interface{}) (*Smart, error) { Attributes: map[string]SmartAttribute{}, } - log.Printf("Prefetched Smart: %v\n", sm) - - //two steps (because we dont know the for key, val := range attrs { - log.Printf("Found Attribute (%s = %v)\n", key, val) - switch key { case "temp": sm.Temp = val.(int64) @@ -100,13 +95,7 @@ func NewSmartFromInfluxDB(attrs map[string]interface{}) (*Smart, error) { } - log.Printf("########NUMBER OF ATTRIBUTES: %v", len(sm.Attributes)) - log.Printf("########SMART: %v", sm) - - //panic("ERROR HERE.") - - //log.Printf("Sm.Attributes: %v", sm.Attributes) - //log.Printf("sm.Attributes[attributeId]: %v", sm.Attributes[attributeId]) + log.Printf("Found Smart Device (%s) Attributes (%v)", sm.DeviceWWN, len(sm.Attributes)) return &sm, nil } From fabc629e4004abb4ff7319901eeb3d50bf773304 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Thu, 5 May 2022 23:03:06 -0700 Subject: [PATCH 090/114] handle case where WWN not detected for a device (print error messages, but skip device collection & uploading). --- collector/pkg/collector/metrics.go | 4 ++++ collector/pkg/detect/detect.go | 6 ++++++ webapp/backend/pkg/web/handler/upload_device_metrics.go | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/collector/pkg/collector/metrics.go b/collector/pkg/collector/metrics.go index a83dd35..ff8158b 100644 --- a/collector/pkg/collector/metrics.go +++ b/collector/pkg/collector/metrics.go @@ -107,6 +107,10 @@ func (mc *MetricsCollector) Validate() error { //func (mc *MetricsCollector) Collect(wg *sync.WaitGroup, deviceWWN string, deviceName string, deviceType string) { func (mc *MetricsCollector) Collect(deviceWWN string, deviceName string, deviceType string) { //defer wg.Done() + if len(deviceWWN) == 0 { + mc.logger.Errorf("no device WWN detected for %s. Skipping collection for this device (no data association possible).\n", deviceName) + return + } mc.logger.Infof("Collecting smartctl results for %s\n", deviceName) args := []string{"-x", "-j"} diff --git a/collector/pkg/detect/detect.go b/collector/pkg/detect/detect.go index 984bee3..d0d80d0 100644 --- a/collector/pkg/detect/detect.go +++ b/collector/pkg/detect/detect.go @@ -100,6 +100,12 @@ func (d *Detect) SmartCtlInfo(device *models.Device) error { d.Logger.Info("Using WWN Fallback") d.wwnFallback(device) } + if len(device.WWN) == 0 { + // no WWN populated after WWN lookup and fallback. we need to throw an error + errMsg := fmt.Sprintf("no WWN (or fallback) populated for device: %s. Device will be registered, but no data will be published for this device. ", device.DeviceName) + d.Logger.Errorf(errMsg) + return fmt.Errorf(errMsg) + } return nil } diff --git a/webapp/backend/pkg/web/handler/upload_device_metrics.go b/webapp/backend/pkg/web/handler/upload_device_metrics.go index 9fab5b5..7a971bd 100644 --- a/webapp/backend/pkg/web/handler/upload_device_metrics.go +++ b/webapp/backend/pkg/web/handler/upload_device_metrics.go @@ -31,7 +31,7 @@ func UploadDeviceMetrics(c *gin.Context) { //update the device information if necessary updatedDevice, err := deviceRepo.UpdateDevice(c, c.Param("wwn"), collectorSmartData) if err != nil { - logger.Errorln("An error occurred while updating device data from smartctl metrics", err) + logger.Errorln("An error occurred while updating device data from smartctl metrics:", err) c.JSON(http.StatusInternalServerError, gin.H{"success": false}) return } From 5bab9ac04a9a1e55dd9b7095bf2b789fe50acc0c Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Thu, 5 May 2022 23:25:00 -0700 Subject: [PATCH 091/114] make sure we can correctly save the config file if onboarding influx. --- webapp/backend/pkg/config/config.go | 2 ++ webapp/backend/pkg/database/scrutiny_repository.go | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/webapp/backend/pkg/config/config.go b/webapp/backend/pkg/config/config.go index 31243e9..88ab60e 100644 --- a/webapp/backend/pkg/config/config.go +++ b/webapp/backend/pkg/config/config.go @@ -104,6 +104,8 @@ func (c *configuration) ReadConfig(configFilePath string) error { if err != nil { return err } + //make sure that we specify that this is the correct config path (for eventual WriteConfig() calls) + c.SetConfigFile(configFilePath) return c.ValidateConfig() } diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index c35923f..fb94f62 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -101,8 +101,10 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field appConfig.Set("web.influxdb.token", *onboardingResponse.Auth.Token) // we should write the config file out here. Ignore failures. - _ = appConfig.WriteConfig() - + err = appConfig.WriteConfig() + if err != nil { + globalLogger.Infof("ignoring error while writing influxdb info to config: %v", err) + } } // Use blocking write client for writes to desired bucket From 57c0f899c6defee54f751a07652a8e11800674c9 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 08:51:42 -0700 Subject: [PATCH 092/114] build multi arch controller image. --- .github/workflows/docker-build.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml index a29e37b..c97d113 100644 --- a/.github/workflows/docker-build.yaml +++ b/.github/workflows/docker-build.yaml @@ -21,6 +21,10 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 # Login against a Docker registry except on PR # https://github.com/docker/login-action - name: Log into registry ${{ env.REGISTRY }} @@ -46,6 +50,7 @@ jobs: uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc with: context: . + platforms: linux/amd64,linux/arm64 file: docker/Dockerfile.collector push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} From d48d0b9d931b6532af0c11ba32954972263d5231 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 09:00:14 -0700 Subject: [PATCH 093/114] build multi arch images --- .github/workflows/docker-build.yaml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml index c97d113..34d1d43 100644 --- a/.github/workflows/docker-build.yaml +++ b/.github/workflows/docker-build.yaml @@ -49,8 +49,8 @@ jobs: - name: Build and push Docker image uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc with: - context: . platforms: linux/amd64,linux/arm64 + context: . file: docker/Dockerfile.collector push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} @@ -65,6 +65,10 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 # Login against a Docker registry except on PR # https://github.com/docker/login-action - name: Log into registry ${{ env.REGISTRY }} @@ -89,6 +93,7 @@ jobs: - name: Build and push Docker image uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc with: + platforms: linux/amd64,linux/arm64 context: . file: docker/Dockerfile.web push: ${{ github.event_name != 'pull_request' }} @@ -104,6 +109,10 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 # Login against a Docker registry except on PR # https://github.com/docker/login-action - name: Log into registry ${{ env.REGISTRY }} @@ -128,6 +137,7 @@ jobs: - name: Build and push Docker image uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc with: + platforms: linux/amd64,linux/arm64 context: . file: docker/Dockerfile push: ${{ github.event_name != 'pull_request' }} From a893d2db47af9c02e2e1574add272e6e6d67703c Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 09:30:37 -0700 Subject: [PATCH 094/114] fix multi-arch builds. --- docker/Dockerfile | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 2e37fba..1f6d557 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -27,18 +27,23 @@ RUN npm install -g @angular/cli@9.1.4 && \ ######## FROM ubuntu:bionic as runtime +ARG TARGETARCH EXPOSE 8080 WORKDIR /scrutiny ENV PATH="/scrutiny/bin:${PATH}" ENV INFLUXD_CONFIG_PATH=/scrutiny/influxdb -RUN apt-get update && apt-get install -y cron smartmontools=7.0-0ubuntu1~ubuntu18.04.1 ca-certificates curl tzdata && update-ca-certificates - -ADD https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s6-overlay-amd64.tar.gz /tmp/ -RUN tar xzf /tmp/s6-overlay-amd64.tar.gz -C / - -ADD https://dl.influxdata.com/influxdb/releases/influxdb2-2.2.0-amd64.deb /tmp/ -RUN dpkg -i /tmp/influxdb2-2.2.0-amd64.deb && rm -rf /tmp/influxdb2-2.2.0-amd64.deb +RUN apt-get update && apt-get install -y cron smartmontools=7.0-0ubuntu1~ubuntu18.04.1 ca-certificates curl tzdata \ + && update-ca-certificates \ + && case ${TARGETARCH} in \ + "amd64") S6_ARCH=amd64 ;; \ + "arm64") S6_ARCH=aarch64 ;; \ + esac \ + && wget -q https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s6-overlay-${S6_ARCH}.tar.gz -O /tmp/ \ + && tar xzf /tmp/s6-overlay-${S6_ARCH}.tar.gz -C / + +ADD https://dl.influxdata.com/influxdb/releases/influxdb2-2.2.0-${TARGETARCH}.deb /tmp/ +RUN dpkg -i /tmp/influxdb2-2.2.0-${TARGETARCH}.deb && rm -rf /tmp/influxdb2-2.2.0-${TARGETARCH}.deb COPY /rootfs / From 2350c1335cf3c912993b8071a5d6c732ec79a8af Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 09:36:22 -0700 Subject: [PATCH 095/114] fix multi-arch builds. --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 1f6d557..be419d7 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -39,7 +39,7 @@ RUN apt-get update && apt-get install -y cron smartmontools=7.0-0ubuntu1~ubuntu1 "amd64") S6_ARCH=amd64 ;; \ "arm64") S6_ARCH=aarch64 ;; \ esac \ - && wget -q https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s6-overlay-${S6_ARCH}.tar.gz -O /tmp/ \ + && wget -q https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s6-overlay-${S6_ARCH}.tar.gz -O /tmp/s6-overlay-${S6_ARCH}.tar.gz \ && tar xzf /tmp/s6-overlay-${S6_ARCH}.tar.gz -C / ADD https://dl.influxdata.com/influxdb/releases/influxdb2-2.2.0-${TARGETARCH}.deb /tmp/ From 77da0f5a573dbdaeda3f304236b2a0c813cae1f4 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 09:48:25 -0700 Subject: [PATCH 096/114] fixing download command (using curl). --- docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index be419d7..e7e85bc 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -35,11 +35,11 @@ ENV INFLUXD_CONFIG_PATH=/scrutiny/influxdb RUN apt-get update && apt-get install -y cron smartmontools=7.0-0ubuntu1~ubuntu18.04.1 ca-certificates curl tzdata \ && update-ca-certificates \ - && case ${TARGETARCH} in \ +RUN case ${TARGETARCH} in \ "amd64") S6_ARCH=amd64 ;; \ "arm64") S6_ARCH=aarch64 ;; \ esac \ - && wget -q https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s6-overlay-${S6_ARCH}.tar.gz -O /tmp/s6-overlay-${S6_ARCH}.tar.gz \ + && curl https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s6-overlay-${S6_ARCH}.tar.gz -L -s --output /tmp/s6-overlay-${S6_ARCH}.tar.gz \ && tar xzf /tmp/s6-overlay-${S6_ARCH}.tar.gz -C / ADD https://dl.influxdata.com/influxdb/releases/influxdb2-2.2.0-${TARGETARCH}.deb /tmp/ From d26e452a4a45da976ac2347ca5bb37a1d543bb5e Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 09:52:01 -0700 Subject: [PATCH 097/114] fixing download command (using curl). --- docker/Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index e7e85bc..65e24c4 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -35,10 +35,10 @@ ENV INFLUXD_CONFIG_PATH=/scrutiny/influxdb RUN apt-get update && apt-get install -y cron smartmontools=7.0-0ubuntu1~ubuntu18.04.1 ca-certificates curl tzdata \ && update-ca-certificates \ -RUN case ${TARGETARCH} in \ - "amd64") S6_ARCH=amd64 ;; \ - "arm64") S6_ARCH=aarch64 ;; \ - esac \ + case ${TARGETARCH} in \ + "amd64") S6_ARCH=amd64 ;; \ + "arm64") S6_ARCH=aarch64 ;; \ + esac \ && curl https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s6-overlay-${S6_ARCH}.tar.gz -L -s --output /tmp/s6-overlay-${S6_ARCH}.tar.gz \ && tar xzf /tmp/s6-overlay-${S6_ARCH}.tar.gz -C / From 8ea194b6ba4ea62163ccfa620a678b05c50cd32c Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 09:54:13 -0700 Subject: [PATCH 098/114] fixing download command (using curl). --- docker/Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 65e24c4..1939676 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -35,10 +35,10 @@ ENV INFLUXD_CONFIG_PATH=/scrutiny/influxdb RUN apt-get update && apt-get install -y cron smartmontools=7.0-0ubuntu1~ubuntu18.04.1 ca-certificates curl tzdata \ && update-ca-certificates \ - case ${TARGETARCH} in \ - "amd64") S6_ARCH=amd64 ;; \ - "arm64") S6_ARCH=aarch64 ;; \ - esac \ + && case ${TARGETARCH} in \ + "amd64") S6_ARCH=amd64 ;; \ + "arm64") S6_ARCH=aarch64 ;; \ + esac \ && curl https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s6-overlay-${S6_ARCH}.tar.gz -L -s --output /tmp/s6-overlay-${S6_ARCH}.tar.gz \ && tar xzf /tmp/s6-overlay-${S6_ARCH}.tar.gz -C / From 87ba8ff63213a8a88e1ff2fe26cc854c7b49637a Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 10:25:08 -0700 Subject: [PATCH 099/114] better message for what's services we're currently waiting for. --- rootfs/etc/services.d/collector-once/run | 2 +- rootfs/etc/services.d/scrutiny/run | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rootfs/etc/services.d/collector-once/run b/rootfs/etc/services.d/collector-once/run index 2fc2dc2..02ac223 100644 --- a/rootfs/etc/services.d/collector-once/run +++ b/rootfs/etc/services.d/collector-once/run @@ -7,7 +7,7 @@ s6-svwait -u /var/run/s6/services/scrutiny s6-svc -O /var/run/s6/services/collector-once # wait until scrutiny is "Ready" -until $(curl --output /dev/null --silent --head --fail http://localhost:8080/api/health); do echo "not ready" && sleep 5; done +until $(curl --output /dev/null --silent --head --fail http://localhost:8080/api/health); do echo "scrutiny api not ready" && sleep 5; done echo "starting scrutiny collector" /scrutiny/bin/scrutiny-collector-metrics run diff --git a/rootfs/etc/services.d/scrutiny/run b/rootfs/etc/services.d/scrutiny/run index 38b3c9d..3fac4a6 100644 --- a/rootfs/etc/services.d/scrutiny/run +++ b/rootfs/etc/services.d/scrutiny/run @@ -1,7 +1,7 @@ #!/usr/bin/with-contenv bash echo "waiting for influxdb" -until $(curl --output /dev/null --silent --head --fail http://localhost:8086/health); do echo "not ready"; done +until $(curl --output /dev/null --silent --head --fail http://localhost:8086/health); do echo "influxdb not ready" && sleep 5; done echo "starting scrutiny" scrutiny start From f39628efc374b0f5281e797823fb11048a7dd7d3 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 15:08:35 -0700 Subject: [PATCH 100/114] by default show all temp data. --- webapp/backend/pkg/database/scrutiny_repository.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/backend/pkg/database/scrutiny_repository.go b/webapp/backend/pkg/database/scrutiny_repository.go index fb94f62..4968eeb 100644 --- a/webapp/backend/pkg/database/scrutiny_repository.go +++ b/webapp/backend/pkg/database/scrutiny_repository.go @@ -331,7 +331,7 @@ func (sr *scrutinyRepository) GetSummary(ctx context.Context) (map[string]*model return nil, err } - deviceTempHistory, err := sr.GetSmartTemperatureHistory(ctx, DURATION_KEY_WEEK) + deviceTempHistory, err := sr.GetSmartTemperatureHistory(ctx, DURATION_KEY_FOREVER) if err != nil { sr.logger.Printf("========================>>>>>>>>======================") sr.logger.Printf("========================>>>>>>>>======================") From 0cee744c2991c12f7a325ec301c53eb4a23b9ed3 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 17:02:56 -0700 Subject: [PATCH 101/114] highlight last updated dates when more than 2 weeks or 1 month. --- .../dashboard/dashboard.component.html | 3 +-- .../modules/dashboard/dashboard.component.ts | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/webapp/frontend/src/app/modules/dashboard/dashboard.component.html b/webapp/frontend/src/app/modules/dashboard/dashboard.component.html index a63f8d2..367688b 100644 --- a/webapp/frontend/src/app/modules/dashboard/dashboard.component.html +++ b/webapp/frontend/src/app/modules/dashboard/dashboard.component.html @@ -67,8 +67,7 @@
{{deviceTitle(summary.value.device)}} -
+
Last Updated on {{summary.value.smart.collector_date | date:'MMMM dd, yyyy - HH:mm' }}
diff --git a/webapp/frontend/src/app/modules/dashboard/dashboard.component.ts b/webapp/frontend/src/app/modules/dashboard/dashboard.component.ts index 382afa4..a0d6738 100644 --- a/webapp/frontend/src/app/modules/dashboard/dashboard.component.ts +++ b/webapp/frontend/src/app/modules/dashboard/dashboard.component.ts @@ -196,6 +196,26 @@ export class DashboardComponent implements OnInit, AfterViewInit, OnDestroy } } + classDeviceLastUpdatedOn(deviceSummary){ + if (deviceSummary.device.device_status !== 0) { + return 'text-red' // if the device has failed, always highlight in red + } else if(deviceSummary.device.device_status === 0 && deviceSummary.smart){ + if(moment().subtract(14, 'd').isBefore(deviceSummary.smart.collector_date)){ + // this device was updated in the last 2 weeks. + return 'text-green' + } else if(moment().subtract(1, 'm').isBefore(deviceSummary.smart.collector_date)){ + // this device was updated in the last month + return 'text-yellow' + } else{ + // last updated more than a month ago. + return 'text-red' + } + + } else { + return '' + } + } + /** * Track by function for ngFor loops * From 786e7d04f22fddba8e11aba4ac38e8b06e37548d Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 17:25:40 -0700 Subject: [PATCH 102/114] make sure we print the overall device status in the details page. --- .../src/app/modules/detail/detail.component.html | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/webapp/frontend/src/app/modules/detail/detail.component.html b/webapp/frontend/src/app/modules/detail/detail.component.html index 87597ca..f7c2066 100644 --- a/webapp/frontend/src/app/modules/detail/detail.component.html +++ b/webapp/frontend/src/app/modules/detail/detail.component.html @@ -56,6 +56,20 @@
/dev/{{device?.device_name}}
+
+
+ + + {{device?.device_status == 0 ? 'passed' : 'failed'}} + +
+
Status
+
+
{{device?.host_id}}
Host ID
From 2214febbd10cd49c027ea9fc5412c5f6d7a1ee40 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 18:38:09 -0700 Subject: [PATCH 103/114] simple rename. --- .../src/app/modules/dashboard/dashboard.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/frontend/src/app/modules/dashboard/dashboard.component.html b/webapp/frontend/src/app/modules/dashboard/dashboard.component.html index 367688b..8e321c4 100644 --- a/webapp/frontend/src/app/modules/dashboard/dashboard.component.html +++ b/webapp/frontend/src/app/modules/dashboard/dashboard.component.html @@ -125,10 +125,10 @@ - + From 21d07a07125a15ee03d3b8002353459af2497584 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 20:07:23 -0700 Subject: [PATCH 104/114] adding tests for Detect struct in collector. Adding ability to mock out exec.Command calls. --- collector/pkg/collector/metrics.go | 6 +- collector/pkg/common/shell/factory.go | 5 ++ collector/pkg/common/shell/interface.go | 11 +++ .../common/{exec.go => shell/local_shell.go} | 6 +- .../local_shell_test.go} | 19 ++-- collector/pkg/common/shell/mock/mock_shell.go | 50 +++++++++++ collector/pkg/detect/detect.go | 7 +- collector/pkg/detect/detect_test.go | 89 +++++++++++++++++++ collector/pkg/detect/devices_darwin.go | 2 + collector/pkg/detect/devices_freebsd.go | 2 + collector/pkg/detect/devices_linux.go | 2 + collector/pkg/detect/devices_windows.go | 2 + .../testdata/smartctl_scan_megaraid.json | 35 ++++++++ .../detect/testdata/smartctl_scan_nvme.json | 29 ++++++ .../detect/testdata/smartctl_scan_simple.json | 65 ++++++++++++++ 15 files changed, 314 insertions(+), 16 deletions(-) create mode 100644 collector/pkg/common/shell/factory.go create mode 100644 collector/pkg/common/shell/interface.go rename collector/pkg/common/{exec.go => shell/local_shell.go} (80%) rename collector/pkg/common/{exec_test.go => shell/local_shell_test.go} (57%) create mode 100644 collector/pkg/common/shell/mock/mock_shell.go create mode 100644 collector/pkg/detect/testdata/smartctl_scan_megaraid.json create mode 100644 collector/pkg/detect/testdata/smartctl_scan_nvme.json create mode 100644 collector/pkg/detect/testdata/smartctl_scan_simple.json diff --git a/collector/pkg/collector/metrics.go b/collector/pkg/collector/metrics.go index ff8158b..656aaad 100644 --- a/collector/pkg/collector/metrics.go +++ b/collector/pkg/collector/metrics.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/analogj/scrutiny/collector/pkg/common" + "github.com/analogj/scrutiny/collector/pkg/common/shell" "github.com/analogj/scrutiny/collector/pkg/config" "github.com/analogj/scrutiny/collector/pkg/detect" "github.com/analogj/scrutiny/collector/pkg/errors" @@ -20,6 +20,7 @@ type MetricsCollector struct { config config.Interface BaseCollector apiEndpoint *url.URL + shell shell.Interface } func CreateMetricsCollector(appConfig config.Interface, logger *logrus.Entry, apiEndpoint string) (MetricsCollector, error) { @@ -34,6 +35,7 @@ func CreateMetricsCollector(appConfig config.Interface, logger *logrus.Entry, ap BaseCollector: BaseCollector{ logger: logger, }, + shell: shell.Create(), } return sc, nil @@ -120,7 +122,7 @@ func (mc *MetricsCollector) Collect(deviceWWN string, deviceName string, deviceT } args = append(args, fmt.Sprintf("%s%s", detect.DevicePrefix(), deviceName)) - result, err := common.ExecCmd(mc.logger, "smartctl", args, "", os.Environ()) + result, err := mc.shell.Command(mc.logger, "smartctl", args, "", os.Environ()) resultBytes := []byte(result) if err != nil { if exitError, ok := err.(*exec.ExitError); ok { diff --git a/collector/pkg/common/shell/factory.go b/collector/pkg/common/shell/factory.go new file mode 100644 index 0000000..921008b --- /dev/null +++ b/collector/pkg/common/shell/factory.go @@ -0,0 +1,5 @@ +package shell + +func Create() Interface { + return new(localShell) +} diff --git a/collector/pkg/common/shell/interface.go b/collector/pkg/common/shell/interface.go new file mode 100644 index 0000000..34d88a2 --- /dev/null +++ b/collector/pkg/common/shell/interface.go @@ -0,0 +1,11 @@ +package shell + +import ( + "github.com/sirupsen/logrus" +) + +// Create mock using: +// mockgen -source=collector/pkg/common/shell/interface.go -destination=collector/pkg/common/shell/mock/mock_shell.go +type Interface interface { + Command(logger *logrus.Entry, cmdName string, cmdArgs []string, workingDir string, environ []string) (string, error) +} diff --git a/collector/pkg/common/exec.go b/collector/pkg/common/shell/local_shell.go similarity index 80% rename from collector/pkg/common/exec.go rename to collector/pkg/common/shell/local_shell.go index 085107a..906fd41 100644 --- a/collector/pkg/common/exec.go +++ b/collector/pkg/common/shell/local_shell.go @@ -1,4 +1,4 @@ -package common +package shell import ( "bytes" @@ -10,7 +10,9 @@ import ( "strings" ) -func ExecCmd(logger *logrus.Entry, cmdName string, cmdArgs []string, workingDir string, environ []string) (string, error) { +type localShell struct{} + +func (s *localShell) Command(logger *logrus.Entry, cmdName string, cmdArgs []string, workingDir string, environ []string) (string, error) { logger.Infof("Executing command: %s %s", cmdName, strings.Join(cmdArgs, " ")) cmd := exec.Command(cmdName, cmdArgs...) diff --git a/collector/pkg/common/exec_test.go b/collector/pkg/common/shell/local_shell_test.go similarity index 57% rename from collector/pkg/common/exec_test.go rename to collector/pkg/common/shell/local_shell_test.go index 846417c..19c8090 100644 --- a/collector/pkg/common/exec_test.go +++ b/collector/pkg/common/shell/local_shell_test.go @@ -1,33 +1,33 @@ -package common_test +package shell import ( - "github.com/analogj/scrutiny/collector/pkg/common" "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "os/exec" "testing" ) -func TestExecCmd(t *testing.T) { +func TestLocalShellCommand(t *testing.T) { t.Parallel() //setup - + testShell := localShell{} //test - result, err := common.ExecCmd(logrus.WithField("exec", "test"), "echo", []string{"hello world"}, "", nil) + result, err := testShell.Command(logrus.WithField("exec", "test"), "echo", []string{"hello world"}, "", nil) //assert require.NoError(t, err) require.Equal(t, "hello world\n", result) } -func TestExecCmd_Date(t *testing.T) { +func TestLocalShellCommand_Date(t *testing.T) { t.Parallel() //setup + testShell := localShell{} //test - _, err := common.ExecCmd(logrus.WithField("exec", "test"), "date", []string{}, "", nil) + _, err := testShell.Command(logrus.WithField("exec", "test"), "date", []string{}, "", nil) //assert require.NoError(t, err) @@ -51,13 +51,14 @@ func TestExecCmd_Date(t *testing.T) { //} // -func TestExecCmd_InvalidCommand(t *testing.T) { +func TestLocalShellCommand_InvalidCommand(t *testing.T) { t.Parallel() //setup + testShell := localShell{} //test - _, err := common.ExecCmd(logrus.WithField("exec", "test"), "invalid_binary", []string{}, "", nil) + _, err := testShell.Command(logrus.WithField("exec", "test"), "invalid_binary", []string{}, "", nil) //assert _, castOk := err.(*exec.ExitError) diff --git a/collector/pkg/common/shell/mock/mock_shell.go b/collector/pkg/common/shell/mock/mock_shell.go new file mode 100644 index 0000000..c22adca --- /dev/null +++ b/collector/pkg/common/shell/mock/mock_shell.go @@ -0,0 +1,50 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: collector/pkg/common/shell/interface.go + +// Package mock_shell is a generated GoMock package. +package mock_shell + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + logrus "github.com/sirupsen/logrus" +) + +// MockInterface is a mock of Interface interface. +type MockInterface struct { + ctrl *gomock.Controller + recorder *MockInterfaceMockRecorder +} + +// MockInterfaceMockRecorder is the mock recorder for MockInterface. +type MockInterfaceMockRecorder struct { + mock *MockInterface +} + +// NewMockInterface creates a new mock instance. +func NewMockInterface(ctrl *gomock.Controller) *MockInterface { + mock := &MockInterface{ctrl: ctrl} + mock.recorder = &MockInterfaceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder { + return m.recorder +} + +// Command mocks base method. +func (m *MockInterface) Command(logger *logrus.Entry, cmdName string, cmdArgs []string, workingDir string, environ []string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Command", logger, cmdName, cmdArgs, workingDir, environ) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Command indicates an expected call of Command. +func (mr *MockInterfaceMockRecorder) Command(logger, cmdName, cmdArgs, workingDir, environ interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Command", reflect.TypeOf((*MockInterface)(nil).Command), logger, cmdName, cmdArgs, workingDir, environ) +} diff --git a/collector/pkg/detect/detect.go b/collector/pkg/detect/detect.go index d0d80d0..1475453 100644 --- a/collector/pkg/detect/detect.go +++ b/collector/pkg/detect/detect.go @@ -3,7 +3,7 @@ package detect import ( "encoding/json" "fmt" - "github.com/analogj/scrutiny/collector/pkg/common" + "github.com/analogj/scrutiny/collector/pkg/common/shell" "github.com/analogj/scrutiny/collector/pkg/config" "github.com/analogj/scrutiny/collector/pkg/models" "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" @@ -15,6 +15,7 @@ import ( type Detect struct { Logger *logrus.Entry Config config.Interface + Shell shell.Interface } //private/common functions @@ -27,7 +28,7 @@ type Detect struct { // models.Device returned from this function only contain the minimum data for smartctl to execute: device type and device name (device file). func (d *Detect) SmartctlScan() ([]models.Device, error) { //we use smartctl to detect all the drives available. - detectedDeviceConnJson, err := common.ExecCmd(d.Logger, "smartctl", []string{"--scan", "-j"}, "", os.Environ()) + detectedDeviceConnJson, err := d.Shell.Command(d.Logger, "smartctl", []string{"--scan", "-j"}, "", os.Environ()) if err != nil { d.Logger.Errorf("Error scanning for devices: %v", err) return nil, err @@ -58,7 +59,7 @@ func (d *Detect) SmartCtlInfo(device *models.Device) error { } args = append(args, fmt.Sprintf("%s%s", DevicePrefix(), device.DeviceName)) - availableDeviceInfoJson, err := common.ExecCmd(d.Logger, "smartctl", args, "", os.Environ()) + availableDeviceInfoJson, err := d.Shell.Command(d.Logger, "smartctl", args, "", os.Environ()) if err != nil { d.Logger.Errorf("Could not retrieve device information for %s: %v", device.DeviceName, err) return err diff --git a/collector/pkg/detect/detect_test.go b/collector/pkg/detect/detect_test.go index 6c034ec..1c00ee7 100644 --- a/collector/pkg/detect/detect_test.go +++ b/collector/pkg/detect/detect_test.go @@ -1,14 +1,103 @@ package detect_test import ( + mock_shell "github.com/analogj/scrutiny/collector/pkg/common/shell/mock" mock_config "github.com/analogj/scrutiny/collector/pkg/config/mock" "github.com/analogj/scrutiny/collector/pkg/detect" "github.com/analogj/scrutiny/collector/pkg/models" "github.com/golang/mock/gomock" + "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" + "io/ioutil" "testing" ) +func TestDetect_SmartctlScan(t *testing.T) { + //setup + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + fakeConfig := mock_config.NewMockInterface(mockCtrl) + fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("") + fakeConfig.EXPECT().GetScanOverrides().AnyTimes().Return([]models.ScanOverride{}) + + fakeShell := mock_shell.NewMockInterface(mockCtrl) + testScanResults, err := ioutil.ReadFile("testdata/smartctl_scan_simple.json") + fakeShell.EXPECT().Command(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(string(testScanResults), err) + + d := detect.Detect{ + Logger: logrus.WithFields(logrus.Fields{}), + Shell: fakeShell, + Config: fakeConfig, + } + + //test + scannedDevices, err := d.SmartctlScan() + + //assert + require.NoError(t, err) + require.Equal(t, 7, len(scannedDevices)) + require.Equal(t, "scsi", scannedDevices[0].DeviceType) +} + +func TestDetect_SmartctlScan_Megaraid(t *testing.T) { + //setup + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + fakeConfig := mock_config.NewMockInterface(mockCtrl) + fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("") + fakeConfig.EXPECT().GetScanOverrides().AnyTimes().Return([]models.ScanOverride{}) + + fakeShell := mock_shell.NewMockInterface(mockCtrl) + testScanResults, err := ioutil.ReadFile("testdata/smartctl_scan_megaraid.json") + fakeShell.EXPECT().Command(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(string(testScanResults), err) + + d := detect.Detect{ + Logger: logrus.WithFields(logrus.Fields{}), + Shell: fakeShell, + Config: fakeConfig, + } + + //test + scannedDevices, err := d.SmartctlScan() + + //assert + require.NoError(t, err) + require.Equal(t, 2, len(scannedDevices)) + require.Equal(t, []models.Device{ + models.Device{DeviceName: "bus/0", DeviceType: "megaraid,0"}, + models.Device{DeviceName: "bus/0", DeviceType: "megaraid,1"}, + }, scannedDevices) +} + +func TestDetect_SmartctlScan_Nvme(t *testing.T) { + //setup + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + fakeConfig := mock_config.NewMockInterface(mockCtrl) + fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("") + fakeConfig.EXPECT().GetScanOverrides().AnyTimes().Return([]models.ScanOverride{}) + + fakeShell := mock_shell.NewMockInterface(mockCtrl) + testScanResults, err := ioutil.ReadFile("testdata/smartctl_scan_nvme.json") + fakeShell.EXPECT().Command(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(string(testScanResults), err) + + d := detect.Detect{ + Logger: logrus.WithFields(logrus.Fields{}), + Shell: fakeShell, + Config: fakeConfig, + } + + //test + scannedDevices, err := d.SmartctlScan() + + //assert + require.NoError(t, err) + require.Equal(t, 1, len(scannedDevices)) + require.Equal(t, []models.Device{ + models.Device{DeviceName: "nvme0", DeviceType: "nvme"}, + }, scannedDevices) +} + func TestDetect_TransformDetectedDevices_Empty(t *testing.T) { //setup mockCtrl := gomock.NewController(t) diff --git a/collector/pkg/detect/devices_darwin.go b/collector/pkg/detect/devices_darwin.go index 6a70f67..928a38d 100644 --- a/collector/pkg/detect/devices_darwin.go +++ b/collector/pkg/detect/devices_darwin.go @@ -1,6 +1,7 @@ package detect import ( + "github.com/analogj/scrutiny/collector/pkg/common/shell" "github.com/analogj/scrutiny/collector/pkg/models" "github.com/jaypipes/ghw" "strings" @@ -11,6 +12,7 @@ func DevicePrefix() string { } func (d *Detect) Start() ([]models.Device, error) { + d.Shell = shell.Create() // call the base/common functionality to get a list of devicess detectedDevices, err := d.SmartctlScan() if err != nil { diff --git a/collector/pkg/detect/devices_freebsd.go b/collector/pkg/detect/devices_freebsd.go index 93e9a00..ebe8e88 100644 --- a/collector/pkg/detect/devices_freebsd.go +++ b/collector/pkg/detect/devices_freebsd.go @@ -1,6 +1,7 @@ package detect import ( + "github.com/analogj/scrutiny/collector/pkg/common/shell" "github.com/analogj/scrutiny/collector/pkg/models" "github.com/jaypipes/ghw" "strings" @@ -11,6 +12,7 @@ func DevicePrefix() string { } func (d *Detect) Start() ([]models.Device, error) { + d.Shell = shell.Create() // call the base/common functionality to get a list of devices detectedDevices, err := d.SmartctlScan() if err != nil { diff --git a/collector/pkg/detect/devices_linux.go b/collector/pkg/detect/devices_linux.go index 93e9a00..ebe8e88 100644 --- a/collector/pkg/detect/devices_linux.go +++ b/collector/pkg/detect/devices_linux.go @@ -1,6 +1,7 @@ package detect import ( + "github.com/analogj/scrutiny/collector/pkg/common/shell" "github.com/analogj/scrutiny/collector/pkg/models" "github.com/jaypipes/ghw" "strings" @@ -11,6 +12,7 @@ func DevicePrefix() string { } func (d *Detect) Start() ([]models.Device, error) { + d.Shell = shell.Create() // call the base/common functionality to get a list of devices detectedDevices, err := d.SmartctlScan() if err != nil { diff --git a/collector/pkg/detect/devices_windows.go b/collector/pkg/detect/devices_windows.go index d9ddbaf..296578e 100644 --- a/collector/pkg/detect/devices_windows.go +++ b/collector/pkg/detect/devices_windows.go @@ -1,6 +1,7 @@ package detect import ( + "github.com/analogj/scrutiny/collector/pkg/common/shell" "github.com/analogj/scrutiny/collector/pkg/models" "strings" ) @@ -10,6 +11,7 @@ func DevicePrefix() string { } func (d *Detect) Start() ([]models.Device, error) { + d.Shell = shell.Create() // call the base/common functionality to get a list of devices detectedDevices, err := d.SmartctlScan() if err != nil { diff --git a/collector/pkg/detect/testdata/smartctl_scan_megaraid.json b/collector/pkg/detect/testdata/smartctl_scan_megaraid.json new file mode 100644 index 0000000..ed4f7f0 --- /dev/null +++ b/collector/pkg/detect/testdata/smartctl_scan_megaraid.json @@ -0,0 +1,35 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 1 + ], + "svn_revision": "5022", + "platform_info": "x86_64-linux-5.4.0-45-generic", + "build_info": "(local build)", + "argv": [ + "smartctl", + "-j", + "--scan" + ], + "exit_status": 0 + }, + "devices": [ + { + "name": "/dev/bus/0", + "info_name": "/dev/bus/0 [megaraid_disk_00]", + "type": "megaraid,0", + "protocol": "SCSI" + }, + { + "name": "/dev/bus/0", + "info_name": "/dev/bus/0 [megaraid_disk_01]", + "type": "megaraid,1", + "protocol": "SCSI" + } + ] +} \ No newline at end of file diff --git a/collector/pkg/detect/testdata/smartctl_scan_nvme.json b/collector/pkg/detect/testdata/smartctl_scan_nvme.json new file mode 100644 index 0000000..edfb8f8 --- /dev/null +++ b/collector/pkg/detect/testdata/smartctl_scan_nvme.json @@ -0,0 +1,29 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 0 + ], + "svn_revision": "4883", + "platform_info": "x86_64-linux-4.19.107-Unraid", + "build_info": "(local build)", + "argv": [ + "smartctl", + "-j", + "--scan" + ], + "exit_status": 0 + }, + "devices": [ + { + "name": "/dev/nvme0", + "info_name": "/dev/nvme0", + "type": "nvme", + "protocol": "NVMe" + } + ] +} \ No newline at end of file diff --git a/collector/pkg/detect/testdata/smartctl_scan_simple.json b/collector/pkg/detect/testdata/smartctl_scan_simple.json new file mode 100644 index 0000000..83e6f2a --- /dev/null +++ b/collector/pkg/detect/testdata/smartctl_scan_simple.json @@ -0,0 +1,65 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 0 + ], + "svn_revision": "4883", + "platform_info": "x86_64-linux-5.15.32-flatcar", + "build_info": "(local build)", + "argv": [ + "smartctl", + "--scan", + "-j" + ], + "exit_status": 0 + }, + "devices": [ + { + "name": "/dev/sda", + "info_name": "/dev/sda", + "type": "scsi", + "protocol": "SCSI" + }, + { + "name": "/dev/sdb", + "info_name": "/dev/sdb", + "type": "scsi", + "protocol": "SCSI" + }, + { + "name": "/dev/sdc", + "info_name": "/dev/sdc", + "type": "scsi", + "protocol": "SCSI" + }, + { + "name": "/dev/sdd", + "info_name": "/dev/sdd", + "type": "scsi", + "protocol": "SCSI" + }, + { + "name": "/dev/sde", + "info_name": "/dev/sde", + "type": "scsi", + "protocol": "SCSI" + }, + { + "name": "/dev/sdf", + "info_name": "/dev/sdf", + "type": "scsi", + "protocol": "SCSI" + }, + { + "name": "/dev/sdg", + "info_name": "/dev/sdg", + "type": "scsi", + "protocol": "SCSI" + } + ] +} \ No newline at end of file From 2b5c864a74bf9e3a6752ee177c03e71317d71752 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 20:38:20 -0700 Subject: [PATCH 105/114] update the codecov action version. --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 6e26655..dc684fe 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -76,7 +76,7 @@ jobs: # /build/scrutiny-collector-metrics-darwin-amd64 # /build/scrutiny-web-freebsd-amd64 # /build/scrutiny-collector-metrics-freebsd-amd64 - - uses: codecov/codecov-action@v1 + - uses: codecov/codecov-action@v2 with: file: ${{ env.PROJECT_PATH }}/coverage.txt flags: unittests From 5ed69d7fc4b303eca54a29ec5a9d2f21be9e07da Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Fri, 6 May 2022 22:15:19 -0700 Subject: [PATCH 106/114] adding tests for Smart and parser. --- .../backend/pkg/models/measurements/smart.go | 10 +- .../pkg/models/measurements/smart_test.go | 573 +++++++++++++----- 2 files changed, 440 insertions(+), 143 deletions(-) diff --git a/webapp/backend/pkg/models/measurements/smart.go b/webapp/backend/pkg/models/measurements/smart.go index c0523b1..aadba20 100644 --- a/webapp/backend/pkg/models/measurements/smart.go +++ b/webapp/backend/pkg/models/measurements/smart.go @@ -109,6 +109,9 @@ func (sm *Smart) FromCollectorSmartInfo(wwn string, info collector.SmartInfo) er sm.Temp = info.Temperature.Current sm.PowerCycleCount = info.PowerCycleCount sm.PowerOnHours = info.PowerOnTime.Hours + if !info.SmartStatus.Passed { + sm.Status = pkg.DeviceStatusFailedSmart + } sm.DeviceProtocol = info.Device.Protocol // process ATA/NVME/SCSI protocol data @@ -126,7 +129,6 @@ func (sm *Smart) FromCollectorSmartInfo(wwn string, info collector.SmartInfo) er //generate SmartAtaAttribute entries from Scrutiny Collector Smart data. func (sm *Smart) ProcessAtaSmartInfo(tableItems []collector.AtaSmartAttributesTableItem) { - sm.Status = pkg.DeviceStatusPassed for _, collectorAttr := range tableItems { attrModel := SmartAtaAttribute{ AttributeId: collectorAttr.ID, @@ -147,7 +149,7 @@ func (sm *Smart) ProcessAtaSmartInfo(tableItems []collector.AtaSmartAttributesTa attrModel.PopulateAttributeStatus() sm.Attributes[strconv.Itoa(collectorAttr.ID)] = &attrModel if attrModel.Status == pkg.SmartAttributeStatusFailed { - sm.Status = pkg.DeviceStatusFailedScrutiny + sm.Status = pkg.Set(sm.Status, pkg.DeviceStatusFailedScrutiny) } } } @@ -177,7 +179,7 @@ func (sm *Smart) ProcessNvmeSmartInfo(nvmeSmartHealthInformationLog collector.Nv //find analyzed attribute status for _, val := range sm.Attributes { if val.GetStatus() == pkg.SmartAttributeStatusFailed { - sm.Status = pkg.DeviceStatusFailedScrutiny + sm.Status = pkg.Set(sm.Status, pkg.DeviceStatusFailedScrutiny) } } } @@ -203,7 +205,7 @@ func (sm *Smart) ProcessScsiSmartInfo(defectGrownList int64, scsiErrorCounterLog //find analyzed attribute status for _, val := range sm.Attributes { if val.GetStatus() == pkg.SmartAttributeStatusFailed { - sm.Status = pkg.DeviceStatusFailedScrutiny + sm.Status = pkg.Set(sm.Status, pkg.DeviceStatusFailedScrutiny) } } } diff --git a/webapp/backend/pkg/models/measurements/smart_test.go b/webapp/backend/pkg/models/measurements/smart_test.go index a1fde28..320528e 100644 --- a/webapp/backend/pkg/models/measurements/smart_test.go +++ b/webapp/backend/pkg/models/measurements/smart_test.go @@ -1,141 +1,436 @@ package measurements_test -//func TestFromCollectorSmartInfo(t *testing.T) { -// //setup -// smartDataFile, err := os.Open("../testdata/smart-ata.json") -// require.NoError(t, err) -// defer smartDataFile.Close() -// -// var smartJson collector.SmartInfo -// -// smartDataBytes, err := ioutil.ReadAll(smartDataFile) -// require.NoError(t, err) -// err = json.Unmarshal(smartDataBytes, &smartJson) -// require.NoError(t, err) -// -// //test -// smartMdl := db.Smart{} -// err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) -// -// //assert -// require.NoError(t, err) -// require.Equal(t, "WWN-test", smartMdl.DeviceWWN) -// require.Equal(t, "passed", smartMdl.SmartStatus) -// require.Equal(t, 18, len(smartMdl.Attributes)) -// -// //check that temperature was correctly parsed -// for _, attr := range smartMdl.Attributes { -// if attr.AttributeId == 194 { -// require.Equal(t, int64(163210330144), attr.RawValue) -// require.Equal(t, int64(32), attr.TransformedValue) -// } -// } -//} -// -//func TestFromCollectorSmartInfo_Fail(t *testing.T) { -// //setup -// smartDataFile, err := os.Open("../testdata/smart-fail.json") -// require.NoError(t, err) -// defer smartDataFile.Close() -// -// var smartJson collector.SmartInfo -// -// smartDataBytes, err := ioutil.ReadAll(smartDataFile) -// require.NoError(t, err) -// err = json.Unmarshal(smartDataBytes, &smartJson) -// require.NoError(t, err) -// -// //test -// smartMdl := db.Smart{} -// err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) -// -// //assert -// require.NoError(t, err) -// require.Equal(t, "WWN-test", smartMdl.DeviceWWN) -// require.Equal(t, "failed", smartMdl.SmartStatus) -// require.Equal(t, 0, len(smartMdl.AtaAttributes)) -// require.Equal(t, 0, len(smartMdl.NvmeAttributes)) -// require.Equal(t, 0, len(smartMdl.ScsiAttributes)) -//} -// -//func TestFromCollectorSmartInfo_Fail2(t *testing.T) { -// //setup -// smartDataFile, err := os.Open("../testdata/smart-fail2.json") -// require.NoError(t, err) -// defer smartDataFile.Close() -// -// var smartJson collector.SmartInfo -// -// smartDataBytes, err := ioutil.ReadAll(smartDataFile) -// require.NoError(t, err) -// err = json.Unmarshal(smartDataBytes, &smartJson) -// require.NoError(t, err) -// -// //test -// smartMdl := db.Smart{} -// err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) -// -// //assert -// require.NoError(t, err) -// require.Equal(t, "WWN-test", smartMdl.DeviceWWN) -// require.Equal(t, "failed", smartMdl.SmartStatus) -// require.Equal(t, 17, len(smartMdl.Attributes)) -//} -// -//func TestFromCollectorSmartInfo_Nvme(t *testing.T) { -// //setup -// smartDataFile, err := os.Open("../testdata/smart-nvme.json") -// require.NoError(t, err) -// defer smartDataFile.Close() -// -// var smartJson collector.SmartInfo -// -// smartDataBytes, err := ioutil.ReadAll(smartDataFile) -// require.NoError(t, err) -// err = json.Unmarshal(smartDataBytes, &smartJson) -// require.NoError(t, err) -// -// //test -// smartMdl := db.Smart{} -// err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) -// -// //assert -// require.NoError(t, err) -// require.Equal(t, "WWN-test", smartMdl.DeviceWWN) -// require.Equal(t, "passed", smartMdl.SmartStatus) -// require.Equal(t, 0, len(smartMdl.AtaAttributes)) -// require.Equal(t, 16, len(smartMdl.NvmeAttributes)) -// require.Equal(t, 0, len(smartMdl.ScsiAttributes)) -// -// require.Equal(t, 111303174, smartMdl.NvmeAttributes[6].Value) -// require.Equal(t, 83170961, smartMdl.NvmeAttributes[7].Value) -//} -// -//func TestFromCollectorSmartInfo_Scsi(t *testing.T) { -// //setup -// smartDataFile, err := os.Open("../testdata/smart-scsi.json") -// require.NoError(t, err) -// defer smartDataFile.Close() -// -// var smartJson collector.SmartInfo -// -// smartDataBytes, err := ioutil.ReadAll(smartDataFile) -// require.NoError(t, err) -// err = json.Unmarshal(smartDataBytes, &smartJson) -// require.NoError(t, err) -// -// //test -// smartMdl := db.Smart{} -// err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) -// -// //assert -// require.NoError(t, err) -// require.Equal(t, "WWN-test", smartMdl.DeviceWWN) -// require.Equal(t, "passed", smartMdl.SmartStatus) -// require.Equal(t, 0, len(smartMdl.AtaAttributes)) -// require.Equal(t, 0, len(smartMdl.NvmeAttributes)) -// require.Equal(t, 13, len(smartMdl.ScsiAttributes)) -// -// require.Equal(t, 56, smartMdl.ScsiAttributes[0].Value) -// require.Equal(t, 300357663, smartMdl.ScsiAttributes[4].Value) //total_errors_corrected -//} +import ( + "encoding/json" + "github.com/analogj/scrutiny/webapp/backend/pkg" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/collector" + "github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements" + "github.com/stretchr/testify/require" + "io/ioutil" + "os" + "testing" + "time" +) + +func TestSmart_Flatten(t *testing.T) { + //setup + timeNow := time.Now() + smart := measurements.Smart{ + Date: timeNow, + DeviceWWN: "test-wwn", + DeviceProtocol: pkg.DeviceProtocolAta, + Temp: 50, + PowerOnHours: 10, + PowerCycleCount: 10, + Attributes: nil, + Status: 0, + } + + //test + tags, fields := smart.Flatten() + + //assert + require.Equal(t, map[string]string{"device_protocol": "ATA", "device_wwn": "test-wwn"}, tags) + require.Equal(t, map[string]interface{}{"power_cycle_count": int64(10), "power_on_hours": int64(10), "temp": int64(50)}, fields) +} + +func TestSmart_Flatten_ATA(t *testing.T) { + //setup + timeNow := time.Now() + smart := measurements.Smart{ + Date: timeNow, + DeviceWWN: "test-wwn", + DeviceProtocol: pkg.DeviceProtocolAta, + Temp: 50, + PowerOnHours: 10, + PowerCycleCount: 10, + Status: 0, + Attributes: map[string]measurements.SmartAttribute{ + "1": &measurements.SmartAtaAttribute{ + AttributeId: 1, + Value: 100, + Threshold: 1, + Worst: 100, + RawValue: 0, + RawString: "0", + WhenFailed: "", + }, + "2": &measurements.SmartAtaAttribute{ + AttributeId: 2, + Value: 135, + Threshold: 54, + Worst: 135, + RawValue: 108, + RawString: "108", + WhenFailed: "", + }, + }, + } + + //test + tags, fields := smart.Flatten() + + //assert + require.Equal(t, map[string]string{"device_protocol": "ATA", "device_wwn": "test-wwn"}, tags) + require.Equal(t, map[string]interface{}{ + "attr.1.attribute_id": "1", + "attr.1.failure_rate": float64(0), + "attr.1.raw_string": "0", + "attr.1.raw_value": int64(0), + "attr.1.status": int64(0), + "attr.1.status_reason": "", + "attr.1.thresh": int64(1), + "attr.1.transformed_value": int64(0), + "attr.1.value": int64(100), + "attr.1.when_failed": "", + "attr.1.worst": int64(100), + + "attr.2.attribute_id": "2", + "attr.2.failure_rate": float64(0), + "attr.2.raw_string": "108", + "attr.2.raw_value": int64(108), + "attr.2.status": int64(0), + "attr.2.status_reason": "", + "attr.2.thresh": int64(54), + "attr.2.transformed_value": int64(0), + "attr.2.value": int64(135), + "attr.2.when_failed": "", + "attr.2.worst": int64(135), + + "power_cycle_count": int64(10), + "power_on_hours": int64(10), + "temp": int64(50), + }, fields) +} + +func TestSmart_Flatten_SCSI(t *testing.T) { + //setup + timeNow := time.Now() + smart := measurements.Smart{ + Date: timeNow, + DeviceWWN: "test-wwn", + DeviceProtocol: pkg.DeviceProtocolScsi, + Temp: 50, + PowerOnHours: 10, + PowerCycleCount: 10, + Status: 0, + Attributes: map[string]measurements.SmartAttribute{ + "read_errors_corrected_by_eccfast": &measurements.SmartScsiAttribute{ + AttributeId: "read_errors_corrected_by_eccfast", + Value: int64(300357663), + }, + }, + } + + //test + tags, fields := smart.Flatten() + + //assert + require.Equal(t, map[string]string{"device_protocol": "SCSI", "device_wwn": "test-wwn"}, tags) + require.Equal(t, map[string]interface{}{ + "attr.read_errors_corrected_by_eccfast.attribute_id": "read_errors_corrected_by_eccfast", + "attr.read_errors_corrected_by_eccfast.failure_rate": float64(0), + "attr.read_errors_corrected_by_eccfast.status": int64(0), + "attr.read_errors_corrected_by_eccfast.status_reason": "", + "attr.read_errors_corrected_by_eccfast.thresh": int64(0), + "attr.read_errors_corrected_by_eccfast.transformed_value": int64(0), + "attr.read_errors_corrected_by_eccfast.value": int64(300357663), + "power_cycle_count": int64(10), + "power_on_hours": int64(10), + "temp": int64(50)}, + fields) +} + +func TestSmart_Flatten_NVMe(t *testing.T) { + //setup + timeNow := time.Now() + smart := measurements.Smart{ + Date: timeNow, + DeviceWWN: "test-wwn", + DeviceProtocol: pkg.DeviceProtocolNvme, + Temp: 50, + PowerOnHours: 10, + PowerCycleCount: 10, + Status: 0, + Attributes: map[string]measurements.SmartAttribute{ + "available_spare": &measurements.SmartNvmeAttribute{ + AttributeId: "available_spare", + Value: int64(100), + }, + }, + } + + //test + tags, fields := smart.Flatten() + + //assert + require.Equal(t, map[string]string{"device_protocol": "NVMe", "device_wwn": "test-wwn"}, tags) + require.Equal(t, map[string]interface{}{ + "attr.available_spare.attribute_id": "available_spare", + "attr.available_spare.failure_rate": float64(0), + "attr.available_spare.status": int64(0), + "attr.available_spare.status_reason": "", + "attr.available_spare.thresh": int64(0), + "attr.available_spare.transformed_value": int64(0), + "attr.available_spare.value": int64(100), + "power_cycle_count": int64(10), + "power_on_hours": int64(10), + "temp": int64(50)}, fields) +} + +func TestNewSmartFromInfluxDB_ATA(t *testing.T) { + //setup + timeNow := time.Now() + attrs := map[string]interface{}{ + "_time": timeNow, + "device_wwn": "test-wwn", + "device_protocol": pkg.DeviceProtocolAta, + "attr.1.attribute_id": "1", + "attr.1.failure_rate": float64(0), + "attr.1.raw_string": "108", + "attr.1.raw_value": int64(108), + "attr.1.status": int64(0), + "attr.1.status_reason": "", + "attr.1.thresh": int64(54), + "attr.1.transformed_value": int64(0), + "attr.1.value": int64(135), + "attr.1.when_failed": "", + "attr.1.worst": int64(135), + "power_cycle_count": int64(10), + "power_on_hours": int64(10), + "temp": int64(50), + } + + //test + smart, err := measurements.NewSmartFromInfluxDB(attrs) + + //assert + require.NoError(t, err) + require.Equal(t, &measurements.Smart{ + Date: timeNow, + DeviceWWN: "test-wwn", + DeviceProtocol: "ATA", + Temp: 50, + PowerOnHours: 10, + PowerCycleCount: 10, + Attributes: map[string]measurements.SmartAttribute{ + "1": &measurements.SmartAtaAttribute{ + AttributeId: 1, + Value: 135, + Threshold: 54, + Worst: 135, + RawValue: 108, + RawString: "108", + WhenFailed: "", + }, + }, Status: 0}, smart) +} + +func TestNewSmartFromInfluxDB_NVMe(t *testing.T) { + //setup + timeNow := time.Now() + attrs := map[string]interface{}{ + "_time": timeNow, + "device_wwn": "test-wwn", + "device_protocol": pkg.DeviceProtocolNvme, + "attr.available_spare.attribute_id": "available_spare", + "attr.available_spare.failure_rate": float64(0), + "attr.available_spare.status": int64(0), + "attr.available_spare.status_reason": "", + "attr.available_spare.thresh": int64(0), + "attr.available_spare.transformed_value": int64(0), + "attr.available_spare.value": int64(100), + "power_cycle_count": int64(10), + "power_on_hours": int64(10), + "temp": int64(50), + } + + //test + smart, err := measurements.NewSmartFromInfluxDB(attrs) + + //assert + require.NoError(t, err) + require.Equal(t, &measurements.Smart{ + Date: timeNow, + DeviceWWN: "test-wwn", + DeviceProtocol: "NVMe", + Temp: 50, + PowerOnHours: 10, + PowerCycleCount: 10, + Attributes: map[string]measurements.SmartAttribute{ + "available_spare": &measurements.SmartNvmeAttribute{ + AttributeId: "available_spare", + Value: int64(100), + }, + }, Status: 0}, smart) +} + +func TestNewSmartFromInfluxDB_SCSI(t *testing.T) { + //setup + timeNow := time.Now() + attrs := map[string]interface{}{ + "_time": timeNow, + "device_wwn": "test-wwn", + "device_protocol": pkg.DeviceProtocolScsi, + "attr.read_errors_corrected_by_eccfast.attribute_id": "read_errors_corrected_by_eccfast", + "attr.read_errors_corrected_by_eccfast.failure_rate": float64(0), + "attr.read_errors_corrected_by_eccfast.status": int64(0), + "attr.read_errors_corrected_by_eccfast.status_reason": "", + "attr.read_errors_corrected_by_eccfast.thresh": int64(0), + "attr.read_errors_corrected_by_eccfast.transformed_value": int64(0), + "attr.read_errors_corrected_by_eccfast.value": int64(300357663), + "power_cycle_count": int64(10), + "power_on_hours": int64(10), + "temp": int64(50), + } + + //test + smart, err := measurements.NewSmartFromInfluxDB(attrs) + + //assert + require.NoError(t, err) + require.Equal(t, &measurements.Smart{ + Date: timeNow, + DeviceWWN: "test-wwn", + DeviceProtocol: "SCSI", + Temp: 50, + PowerOnHours: 10, + PowerCycleCount: 10, + Attributes: map[string]measurements.SmartAttribute{ + "read_errors_corrected_by_eccfast": &measurements.SmartScsiAttribute{ + AttributeId: "read_errors_corrected_by_eccfast", + Value: int64(300357663), + }, + }, Status: 0}, smart) +} + +func TestFromCollectorSmartInfo(t *testing.T) { + //setup + smartDataFile, err := os.Open("../testdata/smart-ata.json") + require.NoError(t, err) + defer smartDataFile.Close() + + var smartJson collector.SmartInfo + + smartDataBytes, err := ioutil.ReadAll(smartDataFile) + require.NoError(t, err) + err = json.Unmarshal(smartDataBytes, &smartJson) + require.NoError(t, err) + + //test + smartMdl := measurements.Smart{} + err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) + + //assert + require.NoError(t, err) + require.Equal(t, "WWN-test", smartMdl.DeviceWWN) + require.Equal(t, pkg.DeviceStatusPassed, smartMdl.Status) + require.Equal(t, 18, len(smartMdl.Attributes)) + + //check that temperature was correctly parsed + + require.Equal(t, int64(163210330144), smartMdl.Attributes["194"].(*measurements.SmartAtaAttribute).RawValue) + require.Equal(t, int64(32), smartMdl.Attributes["194"].(*measurements.SmartAtaAttribute).TransformedValue) +} + +func TestFromCollectorSmartInfo_Fail_Smart(t *testing.T) { + //setup + smartDataFile, err := os.Open("../testdata/smart-fail.json") + require.NoError(t, err) + defer smartDataFile.Close() + + var smartJson collector.SmartInfo + + smartDataBytes, err := ioutil.ReadAll(smartDataFile) + require.NoError(t, err) + err = json.Unmarshal(smartDataBytes, &smartJson) + require.NoError(t, err) + + //test + smartMdl := measurements.Smart{} + err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) + + //assert + require.NoError(t, err) + require.Equal(t, "WWN-test", smartMdl.DeviceWWN) + require.Equal(t, pkg.DeviceStatusFailedSmart, smartMdl.Status) + require.Equal(t, 0, len(smartMdl.Attributes)) +} + +func TestFromCollectorSmartInfo_Fail_ScrutinySmart(t *testing.T) { + //setup + smartDataFile, err := os.Open("../testdata/smart-fail2.json") + require.NoError(t, err) + defer smartDataFile.Close() + + var smartJson collector.SmartInfo + + smartDataBytes, err := ioutil.ReadAll(smartDataFile) + require.NoError(t, err) + err = json.Unmarshal(smartDataBytes, &smartJson) + require.NoError(t, err) + + //test + smartMdl := measurements.Smart{} + err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) + + //assert + require.NoError(t, err) + require.Equal(t, "WWN-test", smartMdl.DeviceWWN) + require.Equal(t, pkg.DeviceStatusFailedScrutiny|pkg.DeviceStatusFailedSmart, smartMdl.Status) + require.Equal(t, 17, len(smartMdl.Attributes)) +} + +func TestFromCollectorSmartInfo_Nvme(t *testing.T) { + //setup + smartDataFile, err := os.Open("../testdata/smart-nvme.json") + require.NoError(t, err) + defer smartDataFile.Close() + + var smartJson collector.SmartInfo + + smartDataBytes, err := ioutil.ReadAll(smartDataFile) + require.NoError(t, err) + err = json.Unmarshal(smartDataBytes, &smartJson) + require.NoError(t, err) + + //test + smartMdl := measurements.Smart{} + err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) + + //assert + require.NoError(t, err) + require.Equal(t, "WWN-test", smartMdl.DeviceWWN) + require.Equal(t, pkg.DeviceStatusPassed, smartMdl.Status) + require.Equal(t, 16, len(smartMdl.Attributes)) + + require.Equal(t, int64(111303174), smartMdl.Attributes["host_reads"].(*measurements.SmartNvmeAttribute).Value) + require.Equal(t, int64(83170961), smartMdl.Attributes["host_writes"].(*measurements.SmartNvmeAttribute).Value) +} + +func TestFromCollectorSmartInfo_Scsi(t *testing.T) { + //setup + smartDataFile, err := os.Open("../testdata/smart-scsi.json") + require.NoError(t, err) + defer smartDataFile.Close() + + var smartJson collector.SmartInfo + + smartDataBytes, err := ioutil.ReadAll(smartDataFile) + require.NoError(t, err) + err = json.Unmarshal(smartDataBytes, &smartJson) + require.NoError(t, err) + + //test + smartMdl := measurements.Smart{} + err = smartMdl.FromCollectorSmartInfo("WWN-test", smartJson) + + //assert + require.NoError(t, err) + require.Equal(t, "WWN-test", smartMdl.DeviceWWN) + require.Equal(t, pkg.DeviceStatusPassed, smartMdl.Status) + require.Equal(t, 13, len(smartMdl.Attributes)) + + require.Equal(t, int64(56), smartMdl.Attributes["scsi_grown_defect_list"].(*measurements.SmartScsiAttribute).Value) + require.Equal(t, int64(300357663), smartMdl.Attributes["read_errors_corrected_by_eccfast"].(*measurements.SmartScsiAttribute).Value) //total_errors_corrected +} From 2967b6ca01ca005a09d45f98e1c2912781fc3cb7 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Sat, 7 May 2022 20:11:17 -0700 Subject: [PATCH 107/114] make sure that we set the config path when ReadConfig is called. --- webapp/backend/pkg/config/config.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/webapp/backend/pkg/config/config.go b/webapp/backend/pkg/config/config.go index 88ab60e..14d26a3 100644 --- a/webapp/backend/pkg/config/config.go +++ b/webapp/backend/pkg/config/config.go @@ -75,6 +75,9 @@ func (c *configuration) Init() error { } func (c *configuration) ReadConfig(configFilePath string) error { + //make sure that we specify that this is the correct config path (for eventual WriteConfig() calls) + c.SetConfigFile(configFilePath) + configFilePath, err := utils.ExpandPath(configFilePath) if err != nil { return err @@ -104,8 +107,6 @@ func (c *configuration) ReadConfig(configFilePath string) error { if err != nil { return err } - //make sure that we specify that this is the correct config path (for eventual WriteConfig() calls) - c.SetConfigFile(configFilePath) return c.ValidateConfig() } From db73175f07caee5fe080ac7529ba6d82bfa75d5a Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Mon, 9 May 2022 09:05:44 -0700 Subject: [PATCH 108/114] fixing release GH Action. --- .github/workflows/release.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7cc9ebb..c30ebfc 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -17,6 +17,19 @@ jobs: name: Build runs-on: ubuntu-latest container: techknowlogick/xgo:go-1.13.x + # Service containers to run with `build` (Required for end-to-end testing) + services: + influxdb: + image: influxdb:2.2 + env: + DOCKER_INFLUXDB_INIT_MODE: setup + DOCKER_INFLUXDB_INIT_USERNAME: admin + DOCKER_INFLUXDB_INIT_PASSWORD: password12345 + DOCKER_INFLUXDB_INIT_ORG: scrutiny + DOCKER_INFLUXDB_INIT_BUCKET: metrics + DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: my-super-secret-auth-token + ports: + - 8086:8086 env: PROJECT_PATH: /go/src/github.com/analogj/scrutiny CGO_ENABLED: 1 From de702414b9c62595d4daee5598f9d45ac0f70862 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Mon, 9 May 2022 09:29:39 -0700 Subject: [PATCH 109/114] moving all filesystem references to /scrutiny to /opt/scrutiny fixes #230 --- CONTRIBUTING.md | 4 +-- README.md | 10 +++--- .../collector-metrics/collector-metrics.go | 4 +-- docker/Dockerfile | 32 +++++++++---------- docker/Dockerfile.collector | 10 +++--- docker/Dockerfile.web | 26 +++++++-------- docker/docker-compose.yml | 2 +- docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md | 2 +- example.collector.yaml | 2 +- example.scrutiny.yaml | 6 ++-- rootfs/etc/cron.d/scrutiny | 2 +- rootfs/etc/services.d/collector-once/run | 2 +- rootfs/etc/services.d/influxdb/run | 10 +++--- webapp/backend/cmd/scrutiny/scrutiny.go | 4 +-- webapp/backend/pkg/config/config.go | 10 +++--- 15 files changed, 63 insertions(+), 63 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e4730dc..8683e89 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,14 +6,14 @@ There are multiple ways to develop on the scrutiny codebase locally. The two mos ## Docker Development ``` -docker build -f docker/Dockerfile . -t analogj/scrutiny +docker build -f docker/Dockerfile . -t chcr.io/analogj/scrutiny:master-omnibus docker run -it --rm -p 8080:8080 \ -v /run/udev:/run/udev:ro \ --cap-add SYS_RAWIO \ --device=/dev/sda \ --device=/dev/sdb \ ghcr.io/analogj/scrutiny:master-omnibus -/scrutiny/bin/scrutiny-collector-metrics run +/opt/scrutiny/bin/scrutiny-collector-metrics run ``` diff --git a/README.md b/README.md index e29e5c7..2bebda4 100644 --- a/README.md +++ b/README.md @@ -72,8 +72,8 @@ If you're using Docker, getting started is as simple as running the following co ```bash docker run -it --rm -p 8080:8080 \ - -v `pwd`/scrutiny:/scrutiny/config \ - -v `pwd`/influxdb2:/scrutiny/influxdb \ + -v `pwd`/scrutiny:/opt/scrutiny/config \ + -v `pwd`/influxdb2:/opt/scrutiny/influxdb \ -v /run/udev:/run/udev:ro \ --cap-add SYS_RAWIO \ --device=/dev/sda \ @@ -102,7 +102,7 @@ docker run --rm -p 8086:8086 \ influxdb:2.2 docker run --rm -p 8080:8080 \ - -v `pwd`/scrutiny:/scrutiny/config \ + -v `pwd`/scrutiny:/opt/scrutiny/config \ --name scrutiny-web \ ghcr.io/analogj/scrutiny:master-web @@ -135,11 +135,11 @@ For users of the docker Hub/Spoke deployment or manual install: initially the da After the first collector run, you'll be greeted with a list of all your hard drives and their current smart status. ```bash -docker exec scrutiny /scrutiny/bin/scrutiny-collector-metrics run +docker exec scrutiny /opt/scrutiny/bin/scrutiny-collector-metrics run ``` # Configuration -By default Scrutiny looks for its YAML configuration files in `/scrutiny/config` +By default Scrutiny looks for its YAML configuration files in `/opt/scrutiny/config` There are two configuration files available: diff --git a/collector/cmd/collector-metrics/collector-metrics.go b/collector/cmd/collector-metrics/collector-metrics.go index cbf11a1..d06be83 100644 --- a/collector/cmd/collector-metrics/collector-metrics.go +++ b/collector/cmd/collector-metrics/collector-metrics.go @@ -29,8 +29,8 @@ func main() { } //we're going to load the config file manually, since we need to validate it. - err = config.ReadConfig("/scrutiny/config/collector.yaml") // Find and read the config file - if _, ok := err.(errors.ConfigFileMissingError); ok { // Handle errors reading the config file + err = config.ReadConfig("/opt/scrutiny/config/collector.yaml") // Find and read the config file + if _, ok := err.(errors.ConfigFileMissingError); ok { // Handle errors reading the config file //ignore "could not find config file" } else if err != nil { os.Exit(1) diff --git a/docker/Dockerfile b/docker/Dockerfile index 1939676..46b6bf9 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -16,22 +16,22 @@ FROM node:lts-slim as frontendbuild #reduce logging, disable angular-cli analytics for ci environment ENV NPM_CONFIG_LOGLEVEL=warn NG_CLI_ANALYTICS=false -WORKDIR /scrutiny/src -COPY webapp/frontend /scrutiny/src +WORKDIR /opt/scrutiny/src +COPY webapp/frontend /opt/scrutiny/src RUN npm install -g @angular/cli@9.1.4 && \ mkdir -p /scrutiny/dist && \ npm install && \ - ng build --output-path=/scrutiny/dist --deploy-url="/web/" --base-href="/web/" --prod + ng build --output-path=/opt/scrutiny/dist --deploy-url="/web/" --base-href="/web/" --prod ######## FROM ubuntu:bionic as runtime ARG TARGETARCH EXPOSE 8080 -WORKDIR /scrutiny -ENV PATH="/scrutiny/bin:${PATH}" -ENV INFLUXD_CONFIG_PATH=/scrutiny/influxdb +WORKDIR /opt/scrutiny +ENV PATH="/opt/scrutiny/bin:${PATH}" +ENV INFLUXD_CONFIG_PATH=/opt/scrutiny/influxdb RUN apt-get update && apt-get install -y cron smartmontools=7.0-0ubuntu1~ubuntu18.04.1 ca-certificates curl tzdata \ && update-ca-certificates \ @@ -48,18 +48,18 @@ RUN dpkg -i /tmp/influxdb2-2.2.0-${TARGETARCH}.deb && rm -rf /tmp/influxdb2-2.2. COPY /rootfs / COPY /rootfs/etc/cron.d/scrutiny /etc/cron.d/scrutiny -COPY --from=backendbuild /go/src/github.com/analogj/scrutiny/scrutiny /scrutiny/bin/ -COPY --from=backendbuild /go/src/github.com/analogj/scrutiny/scrutiny-collector-selftest /scrutiny/bin/ -COPY --from=backendbuild /go/src/github.com/analogj/scrutiny/scrutiny-collector-metrics /scrutiny/bin/ -COPY --from=frontendbuild /scrutiny/dist /scrutiny/web -RUN chmod +x /scrutiny/bin/scrutiny && \ - chmod +x /scrutiny/bin/scrutiny-collector-selftest && \ - chmod +x /scrutiny/bin/scrutiny-collector-metrics && \ +COPY --from=backendbuild /go/src/github.com/analogj/scrutiny/scrutiny /opt/scrutiny/bin/ +COPY --from=backendbuild /go/src/github.com/analogj/scrutiny/scrutiny-collector-selftest /opt/scrutiny/bin/ +COPY --from=backendbuild /go/src/github.com/analogj/scrutiny/scrutiny-collector-metrics /opt/scrutiny/bin/ +COPY --from=frontendbuild /opt/scrutiny/dist /opt/scrutiny/web +RUN chmod +x /opt/scrutiny/bin/scrutiny && \ + chmod +x /opt/scrutiny/bin/scrutiny-collector-selftest && \ + chmod +x /opt/scrutiny/bin/scrutiny-collector-metrics && \ chmod 0644 /etc/cron.d/scrutiny && \ rm -f /etc/cron.daily/* && \ - mkdir -p /scrutiny/web && \ - mkdir -p /scrutiny/config && \ - chmod -R ugo+rwx /scrutiny/config + mkdir -p /opt/scrutiny/web && \ + mkdir -p /opt/scrutiny/config && \ + chmod -R ugo+rwx /opt/scrutiny/config CMD ["/init"] diff --git a/docker/Dockerfile.collector b/docker/Dockerfile.collector index 76bf838..d1cb698 100644 --- a/docker/Dockerfile.collector +++ b/docker/Dockerfile.collector @@ -12,16 +12,16 @@ RUN go mod vendor && \ ######## FROM ubuntu:bionic as runtime WORKDIR /scrutiny -ENV PATH="/scrutiny/bin:${PATH}" +ENV PATH="/opt/scrutiny/bin:${PATH}" RUN apt-get update && apt-get install -y cron smartmontools=7.0-0ubuntu1~ubuntu18.04.1 ca-certificates tzdata && update-ca-certificates COPY /docker/entrypoint-collector.sh /entrypoint-collector.sh COPY /rootfs/etc/cron.d/scrutiny /etc/cron.d/scrutiny -COPY --from=backendbuild /go/src/github.com/analogj/scrutiny/scrutiny-collector-selftest /scrutiny/bin/ -COPY --from=backendbuild /go/src/github.com/analogj/scrutiny/scrutiny-collector-metrics /scrutiny/bin/ -RUN chmod +x /scrutiny/bin/scrutiny-collector-selftest && \ - chmod +x /scrutiny/bin/scrutiny-collector-metrics && \ +COPY --from=backendbuild /go/src/github.com/analogj/scrutiny/scrutiny-collector-selftest /opt/scrutiny/bin/ +COPY --from=backendbuild /go/src/github.com/analogj/scrutiny/scrutiny-collector-metrics /opt/scrutiny/bin/ +RUN chmod +x /opt/scrutiny/bin/scrutiny-collector-selftest && \ + chmod +x /opt/scrutiny/bin/scrutiny-collector-metrics && \ chmod +x /entrypoint-collector.sh && \ chmod 0644 /etc/cron.d/scrutiny && \ rm -f /etc/cron.daily/apt /etc/cron.daily/dpkg /etc/cron.daily/passwd diff --git a/docker/Dockerfile.web b/docker/Dockerfile.web index e942b5f..8307f01 100644 --- a/docker/Dockerfile.web +++ b/docker/Dockerfile.web @@ -14,27 +14,27 @@ FROM node:lts-slim as frontendbuild #reduce logging, disable angular-cli analytics for ci environment ENV NPM_CONFIG_LOGLEVEL=warn NG_CLI_ANALYTICS=false -WORKDIR /scrutiny/src -COPY webapp/frontend /scrutiny/src +WORKDIR /opt/scrutiny/src +COPY webapp/frontend /opt/scrutiny/src RUN npm install -g @angular/cli@9.1.4 && \ - mkdir -p /scrutiny/dist && \ + mkdir -p /opt/scrutiny/dist && \ npm install && \ - ng build --output-path=/scrutiny/dist --deploy-url="/web/" --base-href="/web/" --prod + ng build --output-path=/opt/scrutiny/dist --deploy-url="/web/" --base-href="/web/" --prod ######## FROM ubuntu:bionic as runtime EXPOSE 8080 -WORKDIR /scrutiny -ENV PATH="/scrutiny/bin:${PATH}" +WORKDIR /opt/scrutiny +ENV PATH="/opt/scrutiny/bin:${PATH}" RUN apt-get update && apt-get install -y ca-certificates curl tzdata && update-ca-certificates -COPY --from=backendbuild /go/src/github.com/analogj/scrutiny/scrutiny /scrutiny/bin/ -COPY --from=frontendbuild /scrutiny/dist /scrutiny/web -RUN chmod +x /scrutiny/bin/scrutiny && \ - mkdir -p /scrutiny/web && \ - mkdir -p /scrutiny/config && \ - chmod -R ugo+rwx /scrutiny/config -CMD ["/scrutiny/bin/scrutiny", "start"] +COPY --from=backendbuild /go/src/github.com/analogj/scrutiny/scrutiny /opt/scrutiny/bin/ +COPY --from=frontendbuild /opt/scrutiny/dist /opt/scrutiny/web +RUN chmod +x /opt/scrutiny/bin/scrutiny && \ + mkdir -p /opt/scrutiny/web && \ + mkdir -p /opt/scrutiny/config && \ + chmod -R ugo+rwx /opt/scrutiny/config +CMD ["/opt/scrutiny/bin/scrutiny", "start"] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index e610919..7cba636 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -10,7 +10,7 @@ services: - "8080:8080" volumes: - /run/udev:/run/udev:ro - - ./config:/scrutiny/config + - ./config:/opt/scrutiny/config - ./influxdb:/var/lib/influxdb2 devices: - "/dev/sda" diff --git a/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md b/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md index 73eb4b0..50858f4 100644 --- a/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md +++ b/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md @@ -64,7 +64,7 @@ using a collector config file. See [example.collector.yaml](/example.collector.y > If you're unsure, run `smartctl --scan` on your host, and pass all listed devices to the container. ```yaml -# /scrutiny/config/collector.yaml +# /opt/scrutiny/config/collector.yaml devices: # Dell PERC/Broadcom Megaraid example: https://github.com/AnalogJ/scrutiny/issues/30 - device: /dev/bus/0 diff --git a/example.collector.yaml b/example.collector.yaml index 8cf7abc..113aebf 100644 --- a/example.collector.yaml +++ b/example.collector.yaml @@ -1,6 +1,6 @@ # Commented Scrutiny Configuration File # -# The default location for this file is /scrutiny/config/collector.yaml. +# The default location for this file is /opt/scrutiny/config/collector.yaml. # In some cases to improve clarity default values are specified, # uncommented. Other example values are commented out. # diff --git a/example.scrutiny.yaml b/example.scrutiny.yaml index 2fbe455..587885b 100644 --- a/example.scrutiny.yaml +++ b/example.scrutiny.yaml @@ -1,6 +1,6 @@ # Commented Scrutiny Configuration File # -# The default location for this file is /scrutiny/config/scrutiny.yaml. +# The default location for this file is /opt/scrutiny/config/scrutiny.yaml. # In some cases to improve clarity default values are specified, # uncommented. Other example values are commented out. # @@ -22,10 +22,10 @@ web: host: 0.0.0.0 database: # can also set absolute path here - location: /scrutiny/config/scrutiny.db + location: /opt/scrutiny/config/scrutiny.db src: frontend: - path: /scrutiny/web + path: /opt/scrutiny/web influxdb: host: 0.0.0.0 port: 8086 diff --git a/rootfs/etc/cron.d/scrutiny b/rootfs/etc/cron.d/scrutiny index f112b8e..2ba9927 100644 --- a/rootfs/etc/cron.d/scrutiny +++ b/rootfs/etc/cron.d/scrutiny @@ -11,5 +11,5 @@ MAILTO="" # correctly route collector logs (STDOUT & STDERR) to Cron foreground (collectable by Docker STDOUT) # cron schedule to run daily at midnight: '0 0 * * *' # System environmental variables are stripped by cron, source our dump of the docker environmental variables before each command (/env.sh) -{COLLECTOR_CRON_SCHEDULE} root . /env.sh; /scrutiny/bin/scrutiny-collector-metrics run >/proc/1/fd/1 2>/proc/1/fd/2 +{COLLECTOR_CRON_SCHEDULE} root . /env.sh; /opt/scrutiny/bin/scrutiny-collector-metrics run >/proc/1/fd/1 2>/proc/1/fd/2 # An empty line is required at the end of this file for a valid cron file. diff --git a/rootfs/etc/services.d/collector-once/run b/rootfs/etc/services.d/collector-once/run index 02ac223..7bd73e8 100644 --- a/rootfs/etc/services.d/collector-once/run +++ b/rootfs/etc/services.d/collector-once/run @@ -10,4 +10,4 @@ s6-svc -O /var/run/s6/services/collector-once until $(curl --output /dev/null --silent --head --fail http://localhost:8080/api/health); do echo "scrutiny api not ready" && sleep 5; done echo "starting scrutiny collector" -/scrutiny/bin/scrutiny-collector-metrics run +/opt/scrutiny/bin/scrutiny-collector-metrics run diff --git a/rootfs/etc/services.d/influxdb/run b/rootfs/etc/services.d/influxdb/run index d30ad11..99cf1e1 100644 --- a/rootfs/etc/services.d/influxdb/run +++ b/rootfs/etc/services.d/influxdb/run @@ -1,13 +1,13 @@ #!/usr/bin/with-contenv bash -mkdir -p /scrutiny/influxdb/ +mkdir -p /opt/scrutiny/influxdb/ -if [ -f "/scrutiny/influxdb/config.yaml" ]; then +if [ -f "/opt/scrutiny/influxdb/config.yaml" ]; then echo "influxdb config file already exists. skipping." else -cat << 'EOF' > /scrutiny/influxdb/config.yaml -bolt-path: /scrutiny/influxdb/influxd.bolt -engine-path: /scrutiny/influxdb/engine +cat << 'EOF' > /opt/scrutiny/influxdb/config.yaml +bolt-path: /opt/scrutiny/influxdb/influxd.bolt +engine-path: /opt/scrutiny/influxdb/engine http-bind-address: ":8086" reporting-disabled: true EOF diff --git a/webapp/backend/cmd/scrutiny/scrutiny.go b/webapp/backend/cmd/scrutiny/scrutiny.go index b02475e..103fd6b 100644 --- a/webapp/backend/cmd/scrutiny/scrutiny.go +++ b/webapp/backend/cmd/scrutiny/scrutiny.go @@ -27,8 +27,8 @@ func main() { } //we're going to load the config file manually, since we need to validate it. - err = config.ReadConfig("/scrutiny/config/scrutiny.yaml") // Find and read the config file - if _, ok := err.(errors.ConfigFileMissingError); ok { // Handle errors reading the config file + err = config.ReadConfig("/opt/scrutiny/config/scrutiny.yaml") // Find and read the config file + if _, ok := err.(errors.ConfigFileMissingError); ok { // Handle errors reading the config file //ignore "could not find config file" } else if err != nil { os.Exit(1) diff --git a/webapp/backend/pkg/config/config.go b/webapp/backend/pkg/config/config.go index 14d26a3..71de1be 100644 --- a/webapp/backend/pkg/config/config.go +++ b/webapp/backend/pkg/config/config.go @@ -30,8 +30,8 @@ func (c *configuration) Init() error { //set defaults c.SetDefault("web.listen.port", "8080") c.SetDefault("web.listen.host", "0.0.0.0") - c.SetDefault("web.src.frontend.path", "/scrutiny/web") - c.SetDefault("web.database.location", "/scrutiny/config/scrutiny.db") + c.SetDefault("web.src.frontend.path", "/opt/scrutiny/web") + c.SetDefault("web.database.location", "/opt/scrutiny/config/scrutiny.db") c.SetDefault("log.level", "INFO") c.SetDefault("log.file", "") @@ -49,9 +49,9 @@ func (c *configuration) Init() error { //c.SetDefault("disks.include", []string{}) //c.SetDefault("disks.exclude", []string{}) - //c.SetDefault("notify.metric.script", "/scrutiny/config/notify-metrics.sh") - //c.SetDefault("notify.long.script", "/scrutiny/config/notify-long-test.sh") - //c.SetDefault("notify.short.script", "/scrutiny/config/notify-short-test.sh") + //c.SetDefault("notify.metric.script", "/opt/scrutiny/config/notify-metrics.sh") + //c.SetDefault("notify.long.script", "/opt/scrutiny/config/notify-long-test.sh") + //c.SetDefault("notify.short.script", "/opt/scrutiny/config/notify-short-test.sh") //c.SetDefault("collect.metric.enable", true) //c.SetDefault("collect.metric.command", "-a -o on -S on") From 5acc98d2212d7c282ea44ed736ee370d2d0de8fd Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Mon, 9 May 2022 10:01:29 -0700 Subject: [PATCH 110/114] trying to fix release asset setp. --- .github/workflows/release.yaml | 206 +++------------------------------ 1 file changed, 19 insertions(+), 187 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c30ebfc..bd84d13 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -77,192 +77,24 @@ jobs: GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} # Leave this line unchanged with: version_metadata_path: ${{ github.event.inputs.version_metadata_path }} -# - name: Publish Release -# id: publish -# uses: packagrio/action-publishr-go@master -# env: -# # This is necessary in order to push a commit to the repo -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} # Leave this line unchanged -# with: -# version_metadata_path: ${{ github.event.inputs.version_metadata_path }} -# upload_assets: '/build/scrutiny-web-linux-amd64 /build/scrutiny-collector-metrics-linux-amd64 /build/scrutiny-web-linux-arm64 /build/scrutiny-collector-metrics-linux-arm64 /build/scrutiny-web-linux-arm-5 /build/scrutiny-collector-metrics-linux-arm-5 /build/scrutiny-web-linux-arm-6 /build/scrutiny-collector-metrics-linux-arm-6 /build/scrutiny-web-linux-arm-7 /build/scrutiny-collector-metrics-linux-arm-7 /build/scrutiny-web-windows-4.0-amd64.exe /build/scrutiny-collector-metrics-windows-4.0-amd64.exe' - - - - name: Create Release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - tag_name: ${{ steps.bump_version.outputs.release_version }} - release_name: Release ${{ steps.bump_version.outputs.release_version }} - draft: false - prerelease: false - - - name: Release Asset - Web - linux-amd64 - id: upload-release-asset1 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-web-linux-amd64 - asset_name: scrutiny-web-linux-amd64 - asset_content_type: application/octet-stream - - name: Release Asset - Collector - linux-amd64 - id: upload-release-asset2 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-collector-metrics-linux-amd64 - asset_name: scrutiny-collector-metrics-linux-amd64 - asset_content_type: application/octet-stream - - - - name: Release Asset - Web - linux-arm64 - id: upload-release-asset3 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-web-linux-arm64 - asset_name: scrutiny-web-linux-arm64 - asset_content_type: application/octet-stream - - name: Release Asset - Collector - linux-arm64 - id: upload-release-asset4 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-collector-metrics-linux-arm64 - asset_name: scrutiny-collector-metrics-linux-arm64 - asset_content_type: application/octet-stream - - - name: Release Asset - Web - linux-arm-5 - id: upload-release-asset5 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-web-linux-arm-5 - asset_name: scrutiny-web-linux-arm-5 - asset_content_type: application/octet-stream - - name: Release Asset - Collector - linux-arm-5 - id: upload-release-asset6 - uses: actions/upload-release-asset@v1 + - name: Publish Release + id: publish + uses: packagrio/action-publishr-go@master env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-collector-metrics-linux-arm-5 - asset_name: scrutiny-collector-metrics-linux-arm-5 - asset_content_type: application/octet-stream - - - name: Release Asset - Web - linux-arm-6 - id: upload-release-asset7 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-web-linux-arm-6 - asset_name: scrutiny-web-linux-arm-6 - asset_content_type: application/octet-stream - - name: Release Asset - Collector - linux-arm-6 - id: upload-release-asset8 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-collector-metrics-linux-arm-6 - asset_name: scrutiny-collector-metrics-linux-arm-6 - asset_content_type: application/octet-stream - - - name: Release Asset - Web - linux-arm-7 - id: upload-release-asset9 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-web-linux-arm-7 - asset_name: scrutiny-web-linux-arm-7 - asset_content_type: application/octet-stream - - name: Release Asset - Collector - linux-arm-7 - id: upload-release-asset10 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-collector-metrics-linux-arm-7 - asset_name: scrutiny-collector-metrics-linux-arm-7 - asset_content_type: application/octet-stream - - - name: Release Asset - Web - windows-amd64 - id: upload-release-asset11 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-web-windows-4.0-amd64.exe - asset_name: scrutiny-web-windows-4.0-amd64.exe - asset_content_type: application/octet-stream - - name: Release Asset - Collector - windows-amd64 - id: upload-release-asset12 - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} + # This is necessary in order to push a commit to the repo + GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} # Leave this line unchanged with: - upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps - asset_path: /build/scrutiny-collector-metrics-windows-4.0-amd64.exe - asset_name: scrutiny-collector-metrics-windows-4.0-amd64.exe - asset_content_type: application/octet-stream -# -# - name: Release Asset - Web - darwin-arm64 -# id: upload-release-asset13 -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: /build/scrutiny-web-darwin-arm64 -# asset_name: scrutiny-web-darwin-arm64 -# asset_content_type: application/octet-stream -# - name: Release Asset - Collector - darwin-arm64 -# id: upload-release-asset14 -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: /build/scrutiny-collector-metrics-darwin-arm64 -# asset_name: scrutiny-collector-metrics-darwin-arm64 -# asset_content_type: application/octet-stream -# - name: Release Asset - Web - darwin-amd64 -# id: upload-release-asset15 -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: /build/scrutiny-web-darwin-amd64 -# asset_name: scrutiny-web-darwin-amd64 -# asset_content_type: application/octet-stream -# - name: Release Asset - Collector - darwin-amd64 -# id: upload-release-asset16 -# uses: actions/upload-release-asset@v1 -# env: -# GITHUB_TOKEN: ${{ secrets.SCRUTINY_GITHUB_TOKEN }} -# with: -# upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps -# asset_path: /build/scrutiny-collector-metrics-darwin-amd64 -# asset_name: scrutiny-collector-metrics-darwin-amd64 -# asset_content_type: application/octet-stream \ No newline at end of file + version_metadata_path: ${{ github.event.inputs.version_metadata_path }} + upload_assets: + /build/scrutiny-web-linux-amd64 + /build/scrutiny-collector-metrics-linux-amd64 + /build/scrutiny-web-linux-arm64 + /build/scrutiny-collector-metrics-linux-arm64 + /build/scrutiny-web-linux-arm-5 + /build/scrutiny-collector-metrics-linux-arm-5 + /build/scrutiny-web-linux-arm-6 + /build/scrutiny-collector-metrics-linux-arm-6 + /build/scrutiny-web-linux-arm-7 + /build/scrutiny-collector-metrics-linux-arm-7 + /build/scrutiny-web-windows-4.0-amd64.exe + /build/scrutiny-collector-metrics-windows-4.0-amd64.exe From 833fb96c151f7fbd9e9ec026ff459db28d253c2e Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Mon, 9 May 2022 12:55:40 -0700 Subject: [PATCH 111/114] fixing publish release step. --- .github/workflows/release.yaml | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index bd84d13..ea275c6 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -69,6 +69,9 @@ jobs: # restore modified dir to GH workspace. cp -arf $PROJECT_PATH/. $GITHUB_WORKSPACE/ + # copy all the build artifacts to the GH workspace + cp -arf /build/. $GITHUB_WORKSPACE/ + - name: Commit Changes id: commit uses: packagrio/action-releasr-go@master @@ -86,15 +89,15 @@ jobs: with: version_metadata_path: ${{ github.event.inputs.version_metadata_path }} upload_assets: - /build/scrutiny-web-linux-amd64 - /build/scrutiny-collector-metrics-linux-amd64 - /build/scrutiny-web-linux-arm64 - /build/scrutiny-collector-metrics-linux-arm64 - /build/scrutiny-web-linux-arm-5 - /build/scrutiny-collector-metrics-linux-arm-5 - /build/scrutiny-web-linux-arm-6 - /build/scrutiny-collector-metrics-linux-arm-6 - /build/scrutiny-web-linux-arm-7 - /build/scrutiny-collector-metrics-linux-arm-7 - /build/scrutiny-web-windows-4.0-amd64.exe - /build/scrutiny-collector-metrics-windows-4.0-amd64.exe + scrutiny-web-linux-amd64 + scrutiny-collector-metrics-linux-amd64 + scrutiny-web-linux-arm64 + scrutiny-collector-metrics-linux-arm64 + scrutiny-web-linux-arm-5 + scrutiny-collector-metrics-linux-arm-5 + scrutiny-web-linux-arm-6 + scrutiny-collector-metrics-linux-arm-6 + scrutiny-web-linux-arm-7 + scrutiny-collector-metrics-linux-arm-7 + scrutiny-web-windows-4.0-amd64.exe + scrutiny-collector-metrics-windows-4.0-amd64.exe From a2a80f310203ada3db996245ddec829162ff64da Mon Sep 17 00:00:00 2001 From: packagrio-bot Date: Mon, 9 May 2022 20:05:53 +0000 Subject: [PATCH 112/114] (v0.4.0) Automated packaging of release by Packagr --- go.mod | 1 - go.sum | 730 -------------------------- webapp/backend/pkg/version/version.go | 2 +- 3 files changed, 1 insertion(+), 732 deletions(-) delete mode 100644 go.sum diff --git a/go.mod b/go.mod index fce6bc7..ebc234b 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,6 @@ require ( github.com/go-gormigrate/gormigrate/v2 v2.0.0 github.com/golang/mock v1.4.3 github.com/google/uuid v1.2.0 // indirect - github.com/hashicorp/serf v0.8.2 // indirect github.com/influxdata/influxdb-client-go/v2 v2.2.3 github.com/jaypipes/ghw v0.6.1 github.com/jinzhu/gorm v1.9.16 diff --git a/go.sum b/go.sum deleted file mode 100644 index f30e6c4..0000000 --- a/go.sum +++ /dev/null @@ -1,730 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= -github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= -github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/agnivade/wasmbrowsertest v0.3.1/go.mod h1:zQt6ZTdl338xxRaMW395qccVE2eQm0SjC/SDz0mPWQI= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/analogj/go-util v0.0.0-20190301173314-5295e364eb14 h1:wsrSjiqQtseStRIoLLxS4C5IEtXkazZVEPDHq8jW7r8= -github.com/analogj/go-util v0.0.0-20190301173314-5295e364eb14/go.mod h1:lJQVqFKMV5/oDGYR2bra2OljcF3CvolAoyDRyOA4k4E= -github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/chromedp/cdproto v0.0.0-20190614062957-d6d2f92b486d/go.mod h1:S8mB5wY3vV+vRIzf39xDXsw3XKYewW9X6rW2aEmkrSw= -github.com/chromedp/cdproto v0.0.0-20190621002710-8cbd498dd7a0/go.mod h1:S8mB5wY3vV+vRIzf39xDXsw3XKYewW9X6rW2aEmkrSw= -github.com/chromedp/cdproto v0.0.0-20190812224334-39ef923dcb8d/go.mod h1:0YChpVzuLJC5CPr+x3xkHN6Z8KOSXjNbL7qV8Wc4GW0= -github.com/chromedp/cdproto v0.0.0-20190926234355-1b4886c6fad6/go.mod h1:0YChpVzuLJC5CPr+x3xkHN6Z8KOSXjNbL7qV8Wc4GW0= -github.com/chromedp/chromedp v0.3.1-0.20190619195644-fd957a4d2901/go.mod h1:mJdvfrVn594N9tfiPecUidF6W5jPRKHymqHfzbobPsM= -github.com/chromedp/chromedp v0.4.0/go.mod h1:DC3QUn4mJ24dwjcaGQLoZrhm4X/uPHZ6spDbS2uFhm4= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/containrrr/shoutrrr v0.0.0-20200828202222-1da53231b05a h1:6ZMiughZYF6fJjFIf2X3D7AfImJeXnTMJ9qC2v75WPw= -github.com/containrrr/shoutrrr v0.0.0-20200828202222-1da53231b05a/go.mod h1:z3pUtEhu5zOpu+Q8wZWiEq+ZLL9hM0HiFNhttaI67Ks= -github.com/containrrr/shoutrrr v0.4.4 h1:vHZ4E/76pKVY+Jyn/qhBz3X540Bn8NI5ppPHK4PyILY= -github.com/containrrr/shoutrrr v0.4.4/go.mod h1:zqL2BvfC1W4FujrT4b3/ZCLxvD+uoeEpBL7rg9Dqpbg= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deepmap/oapi-codegen v1.3.13 h1:9HKGCsdJqE4dnrQ8VerFS0/1ZOJPmAhN+g8xgp8y3K4= -github.com/deepmap/oapi-codegen v1.3.13/go.mod h1:WAmG5dWY8/PYHt4vKxlt90NsbHMAOCiteYKZMiIRfOo= -github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= -github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= -github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gormigrate/gormigrate/v2 v2.0.0 h1:e2A3Uznk4viUC4UuemuVgsNnvYZyOA8B3awlYk3UioU= -github.com/go-gormigrate/gormigrate/v2 v2.0.0/go.mod h1:YuVJ+D/dNt4HWrThTBnjgZuRbt7AuwINeg4q52ZE3Jw= -github.com/go-interpreter/wagon v0.5.1-0.20190713202023-55a163980b6c/go.mod h1:5+b/MBYkclRZngKF5s6qrgWxSLgE9F5dFdO1hAueZLc= -github.com/go-interpreter/wagon v0.6.0/go.mod h1:5+b/MBYkclRZngKF5s6qrgWxSLgE9F5dFdO1hAueZLc= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= -github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190908185732-236ed259b199/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.5 h1:kxhtnfFVi+rYdOALN0B3k9UT86zVJKfBimRaciULW4I= -github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb-client-go v1.4.0 h1:+KavOkwhLClHFfYcJMHHnTL5CZQhXJzOm5IKHI9BqJk= -github.com/influxdata/influxdb-client-go/v2 v2.2.3 h1:082jdJ5t1CFeo0rpGQvKAK1mONVSbFhL4finWA5bRM8= -github.com/influxdata/influxdb-client-go/v2 v2.2.3/go.mod h1:fa/d1lAdUHxuc1jedx30ZfNG573oQTQmUni3N6pcW+0= -github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU= -github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= -github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= -github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= -github.com/jackc/pgconn v1.6.4/go.mod h1:w2pne1C2tZgP+TvjqLpOigGzNqjBgQW9dUw/4Chex78= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.0.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= -github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= -github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= -github.com/jackc/pgtype v1.4.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= -github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= -github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= -github.com/jackc/pgx/v4 v4.8.1/go.mod h1:4HOLxrl8wToZJReD04/yB20GDwf4KBYETvlHciCnwW0= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jarcoal/httpmock v1.0.4 h1:jp+dy/+nonJE4g4xbVtl9QdrUNbn6/3hDT5R4nDIZnA= -github.com/jarcoal/httpmock v1.0.4/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= -github.com/jaypipes/ghw v0.6.1 h1:Ewt3mdpiyhWotGyzg1ursV/6SnToGcG4215X6rR2af8= -github.com/jaypipes/ghw v0.6.1/go.mod h1:QOXppNRCLGYR1H+hu09FxZPqjNt09bqUZUnOL3Rcero= -github.com/jaypipes/pcidb v0.5.0 h1:4W5gZ+G7QxydevI8/MmmKdnIPJpURqJ2JNXTzfLxF5c= -github.com/jaypipes/pcidb v0.5.0/go.mod h1:L2RGk04sfRhp5wvHO0gfRAMoLY/F3PKv/nwJeVoho0o= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= -github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= -github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg= -github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.12.1 h1:/+xsCsk06wE38cyiqOR/o7U2fSftcH72xD+BQXmja/g= -github.com/klauspost/compress v1.12.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/knq/sysutil v0.0.0-20181215143952-f05b59f0f307/go.mod h1:BjPj+aVjl9FW/cCGiF3nGh5v+9Gd3VCgBQbod/GlMaQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kvz/logstreamer v0.0.0-20150507115422-a635b98146f0 h1:3tLzEnUizyN9YLWFTT9loC30lSBvh2y70LTDcZOTs1s= -github.com/kvz/logstreamer v0.0.0-20150507115422-a635b98146f0/go.mod h1:8/LTPeDLaklcUjgSQBHbhBF1ibKAFxzS5o+H7USfMSA= -github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= -github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= -github.com/mattn/go-sqlite3 v1.14.3 h1:j7a/xn1U6TKA/PHHxqZuzh64CdtRc7rU9M+AvkOl5bA= -github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= -github.com/mattn/go-sqlite3 v1.14.4 h1:4rQjbDxdu9fSgI/r3KN72G3c2goxknAqHHgPWWs8UlI= -github.com/mattn/go-sqlite3 v1.14.4/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= -github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.6 h1:11TGpSHY7Esh/i/qnq02Jo5oVrI1Gue8Slbq0ujPZFQ= -github.com/nxadm/tail v1.4.6/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= -github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.1 h1:foqVmeWDD6yYpK+Yz3fHyNIxFYNxswxqNFjSKe+vI54= -github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= -github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= -github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= -github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/twitchyliquid64/golang-asm v0.0.0-20190126203739-365674df15fc/go.mod h1:NoCfSFWosfqMqmmD7hApkirIK9ozpHjxRnRxs1l413A= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= -github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.coder.com/go-tools v0.0.0-20190317003359-0c6a35b74a16/go.mod h1:iKV5yK9t+J5nG9O3uF6KYdPEz3dyfMyB15MN1rbQ8Qw= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180426230345-b49d69b5da94/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM= -golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190306220234-b354f8bf4d9e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190618155005-516e3c20635f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190927073244-c990c680b611/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= -golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 h1:nVuTkr9L6Bq62qpUqKo/RnZCFfzDBL0bYo6w9OJUqZY= -golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ= -gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gorm.io/driver/mysql v1.0.1/go.mod h1:KtqSthtg55lFp3S5kUXqlGaelnWpKitn4k1xZTnoiPw= -gorm.io/driver/postgres v1.0.0/go.mod h1:wtMFcOzmuA5QigNsgEIb7O5lhvH1tHAF1RbWmLWV4to= -gorm.io/driver/sqlite v1.1.1/go.mod h1:hm2olEcl8Tmsc6eZyxYSeznnsDaMqamBvEXLNtBg4cI= -gorm.io/driver/sqlite v1.1.3 h1:BYfdVuZB5He/u9dt4qDpZqiqDJ6KhPqs5QUqsr/Eeuc= -gorm.io/driver/sqlite v1.1.3/go.mod h1:AKDgRWk8lcSQSw+9kxCJnX/yySj8G3rdwYlU57cB45c= -gorm.io/driver/sqlserver v1.0.2/go.mod h1:gb0Y9QePGgqjzrVyTQUZeh9zkd5v0iz71cM1B4ZycEY= -gorm.io/gorm v1.9.19/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.20.0/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.20.1/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.20.2 h1:bZzSEnq7NDGsrd+n3evOOedDrY5oLM5QPlCjZJUK2ro= -gorm.io/gorm v1.20.2/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gosrc.io/xmpp v0.1.1 h1:iMtE9W3fx254+4E6rI34AOPJDqWvpfQR6EYaVMzhJ4s= -gosrc.io/xmpp v0.1.1/go.mod h1:4JgaXzw4MnEv2sGltONtK3GMhj+h9gpQ7cO8nwbFJLU= -gosrc.io/xmpp v0.5.1 h1:Rgrm5s2rt+npGggJH3HakQxQXR8ZZz3+QRzakRQqaq4= -gosrc.io/xmpp v0.5.1/go.mod h1:L3NFMqYOxyLz3JGmgFyWf7r9htE91zVGiK40oW4RwdY= -gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/gotestsum v0.3.5/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= -howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= -mvdan.cc/sh v2.6.4+incompatible/go.mod h1:IeeQbZq+x2SUGBensq/jge5lLQbS3XT2ktyp3wrt4x8= -nhooyr.io/websocket v1.6.5/go.mod h1:F259lAzPRAH0htX2y3ehpJe09ih1aSHN7udWki1defY= -nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= -nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= -nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= -nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/webapp/backend/pkg/version/version.go b/webapp/backend/pkg/version/version.go index d2ba094..e68c616 100644 --- a/webapp/backend/pkg/version/version.go +++ b/webapp/backend/pkg/version/version.go @@ -2,4 +2,4 @@ package version // VERSION is the app-global version string, which will be replaced with a // new value during packaging -const VERSION = "0.3.12" +const VERSION = "0.4.0" From 3e444b199ae0d6481e4ba5bad5f17d19d00b84a1 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Mon, 9 May 2022 13:48:28 -0700 Subject: [PATCH 113/114] make sure releases (tag events) have unique docker image builds. --- .github/workflows/docker-build.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml index 34d1d43..4109e87 100644 --- a/.github/workflows/docker-build.yaml +++ b/.github/workflows/docker-build.yaml @@ -42,6 +42,7 @@ jobs: with: tags: | type=ref,enable=true,event=branch,suffix=-collector + type=ref,enable=true,event=tag,suffix=-collector images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # Build and push Docker image with Buildx (don't push on PR) @@ -86,6 +87,7 @@ jobs: with: tags: | type=ref,enable=true,event=branch,suffix=-web + type=ref,enable=true,event=tag,suffix=-web images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # Build and push Docker image with Buildx (don't push on PR) @@ -130,6 +132,7 @@ jobs: with: tags: | type=ref,enable=true,event=branch,suffix=-omnibus + type=ref,enable=true,event=tag,suffix=-omnibus images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # Build and push Docker image with Buildx (don't push on PR) From a6e34f7a44773c35538d50da14cd3d1b0e9f8341 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Mon, 9 May 2022 14:09:58 -0700 Subject: [PATCH 114/114] fix for labeling issue. --- .github/workflows/sponsors.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sponsors.yaml b/.github/workflows/sponsors.yaml index 8cf880d..b5c7479 100644 --- a/.github/workflows/sponsors.yaml +++ b/.github/workflows/sponsors.yaml @@ -9,6 +9,6 @@ jobs: name: is-sponsor-label runs-on: ubuntu-latest steps: - - uses: JasonEtco/is-sponsor-label-action@v1 + - uses: JasonEtco/is-sponsor-label-action@v1.2.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}