From bfba5c99fb4e5f8c313941657474a08fff577ce4 Mon Sep 17 00:00:00 2001 From: Roger Far Date: Fri, 10 Apr 2020 16:48:33 -0600 Subject: [PATCH] Switched out RDNET Dll with Nuget package, update Angular. Rewrote Download handler and removed references to Hangfire. --- .gitignore | 10 +- client/package-lock.json | 1183 +++++++++++------ client/package.json | 29 +- client/src/app/app.module.ts | 3 + client/src/app/file-status.pipe.ts | 6 +- client/src/app/models/download.model.ts | 9 +- client/src/app/models/torrent.model.ts | 8 +- .../torrent-row/torrent-row.component.html | 3 + client/src/app/torrent-status.pipe.ts | 63 +- .../torrent-table.component.html | 4 + .../torrent-table/torrent-table.component.ts | 23 +- client/tslint.json | 73 +- server/RdtClient.Data/Data/DownloadData.cs | 9 + server/RdtClient.Data/Data/TorrentData.cs | 7 +- server/RdtClient.Data/Enums/TorrentStatus.cs | 7 +- ....cs => 20200408224831_Initial.Designer.cs} | 8 +- ...0_Initial.cs => 20200408224831_Initial.cs} | 2 + .../Migrations/DataContextModelSnapshot.cs | 6 + server/RdtClient.Data/Models/Data/Download.cs | 11 +- server/RdtClient.Data/Models/Data/Torrent.cs | 6 +- server/RdtClient.Data/RdtClient.Data.csproj | 26 +- server/RdtClient.Service/DiConfig.cs | 3 +- .../RdtClient.Service.csproj | 8 +- .../Services/DownloadManager.cs | 96 +- .../RdtClient.Service/Services/Downloads.cs | 10 +- .../RdtClient.Service/Services/QBittorrent.cs | 6 +- .../RdtClient.Service/Services/Scheduler.cs | 62 - .../RdtClient.Service/Services/TaskRunner.cs | 180 +++ server/RdtClient.Service/Services/Torrents.cs | 64 +- .../Controllers/QBittorrentController.cs | 2 +- .../Controllers/SettingsController.cs | 6 +- .../Controllers/TorrentsController.cs | 13 +- server/RdtClient.Web/Program.cs | 1 - server/RdtClient.Web/RdtClient.Web.csproj | 4 - server/RdtClient.Web/Startup.cs | 23 +- server/RdtClient.Web/wwwroot/index.html | 2 +- server/libs/RDNET.deps.json | 63 - server/libs/RDNET.dll | Bin 66560 -> 0 bytes server/libs/RDNET.pdb | Bin 16600 -> 0 bytes 39 files changed, 1183 insertions(+), 856 deletions(-) rename server/RdtClient.Data/Migrations/{20200407174750_Initial.Designer.cs => 20200408224831_Initial.Designer.cs} (98%) rename server/RdtClient.Data/Migrations/{20200407174750_Initial.cs => 20200408224831_Initial.cs} (98%) delete mode 100644 server/RdtClient.Service/Services/Scheduler.cs create mode 100644 server/RdtClient.Service/Services/TaskRunner.cs delete mode 100644 server/libs/RDNET.deps.json delete mode 100644 server/libs/RDNET.dll delete mode 100644 server/libs/RDNET.pdb diff --git a/.gitignore b/.gitignore index 21c5f32..b9a3b14 100644 --- a/.gitignore +++ b/.gitignore @@ -33,11 +33,7 @@ client/e2e/*.map # .NET Core build folders server/**/bin server/**/obj -server/*.user - -# Common node modules locations -server/wwwroot/ -server/.vs +server/**/*.user +server/**/.vs server/RdtClient.Web/wwwroot/ -server/RdtClient.Web/Properties/PublishProfiles/FolderProfile.pubxml.user -*.user + diff --git a/client/package-lock.json b/client/package-lock.json index 76db1d7..3f8006f 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -5,12 +5,12 @@ "requires": true, "dependencies": { "@angular-devkit/architect": { - "version": "0.901.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.901.0.tgz", - "integrity": "sha512-SlqEBkPrT40zMCy5344AsUqC76pEPCaGPaAkCIvadaz2dC9vNMzQrvubCPJHViD/TumkSX1kYmLS3iYASVM9GQ==", + "version": "0.901.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.901.1.tgz", + "integrity": "sha512-foWDAurMfBDYLAJxHpTFkJBub1c2A8+eWHbBjgqIHmT8xadnE7t8nSA9XDl+k/kIoWw/qFU+6IttPirudYc/vw==", "dev": true, "requires": { - "@angular-devkit/core": "9.1.0", + "@angular-devkit/core": "9.1.1", "rxjs": "6.5.4" }, "dependencies": { @@ -26,21 +26,21 @@ } }, "@angular-devkit/build-angular": { - "version": "0.901.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.901.0.tgz", - "integrity": "sha512-ftJVNlKvIomqRfr5jFVraPqlLSUJu8YyVbFv/aCsvhNpuZGkYpTOMoJDwyywdslSTH608BIoU63IAnIz9PwUdw==", + "version": "0.901.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.901.1.tgz", + "integrity": "sha512-6uEvo5htsJoxQHBVwHOGmM6YWq5q6m9UWMv/ughlek0RtSLFfOt9TZQ/yQHgtGQsCQvscD/jBzVoD0zD5Ax/SQ==", "dev": true, "requires": { - "@angular-devkit/architect": "0.901.0", - "@angular-devkit/build-optimizer": "0.901.0", - "@angular-devkit/build-webpack": "0.901.0", - "@angular-devkit/core": "9.1.0", + "@angular-devkit/architect": "0.901.1", + "@angular-devkit/build-optimizer": "0.901.1", + "@angular-devkit/build-webpack": "0.901.1", + "@angular-devkit/core": "9.1.1", "@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.0", + "@ngtools/webpack": "9.1.1", "ajv": "6.12.0", "autoprefixer": "9.7.4", "babel-loader": "8.0.6", @@ -82,7 +82,7 @@ "style-loader": "1.1.3", "stylus": "0.54.7", "stylus-loader": "3.0.2", - "terser": "4.6.7", + "terser": "4.6.10", "terser-webpack-plugin": "2.3.5", "tree-kill": "1.2.2", "webpack": "4.42.0", @@ -106,26 +106,34 @@ } }, "@angular-devkit/build-optimizer": { - "version": "0.901.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.901.0.tgz", - "integrity": "sha512-Y9sz8uf2zjilhPUVYb0K9Mio6c1d5c+csuDc15CCKzELXJwyyDxilIFgn6Eu+edM0HNQGzbIwkjy4DkR9mtuTQ==", + "version": "0.901.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.901.1.tgz", + "integrity": "sha512-o0A9CcyDQSUnC5CQIKf92VH8amIYRYrMgLf2kdhSMcy0QV+rEJyN81dSvwX/Yxgnr9NbWEAQg7jnyKk06vfhOw==", "dev": true, "requires": { "loader-utils": "2.0.0", "source-map": "0.7.3", "tslib": "1.11.1", - "typescript": "3.8.3", + "typescript": "3.6.5", "webpack-sources": "1.4.3" + }, + "dependencies": { + "typescript": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.5.tgz", + "integrity": "sha512-BEjlc0Z06ORZKbtcxGrIvvwYs5hAnuo6TKdNFL55frVDlB+na3z5bsLhFaIxmT+dPWgBIjMo6aNnTOgHHmHgiQ==", + "dev": true + } } }, "@angular-devkit/build-webpack": { - "version": "0.901.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.901.0.tgz", - "integrity": "sha512-Oze0VzIvHnoW12C80fiNH4HBu/GWmhJPXdNA7nRkU/tBQlIKnfngf8rQ0QbgecN2qdEXQpZJsP/XclTi3zugsg==", + "version": "0.901.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.901.1.tgz", + "integrity": "sha512-9oNI+wPSk8yECy+f0EebfMx4PH3uDJRrifYZAxcr84IpzEbpfpRuYhE3ecwqd7k0zu2Kdjw1uUrGxBuH4/sbGg==", "dev": true, "requires": { - "@angular-devkit/architect": "0.901.0", - "@angular-devkit/core": "9.1.0", + "@angular-devkit/architect": "0.901.1", + "@angular-devkit/core": "9.1.1", "rxjs": "6.5.4" }, "dependencies": { @@ -141,9 +149,9 @@ } }, "@angular-devkit/core": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-9.1.0.tgz", - "integrity": "sha512-vHTsrB4JaVUQ95FRnKrgo79Y3F6FokImrZdrmwkQmwAThpjXeXmpUEKZS+ZSTFRgesjiIysVGOFijARP4BQ7Bg==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-9.1.1.tgz", + "integrity": "sha512-57MNew2u1QwVb69jxZyhXgdW9kqcGyWyRy2ui/hWCkWLg7RumWtyypmdTs89FNExB4HqtXlQ2eO3JZxfs7QR3w==", "dev": true, "requires": { "ajv": "6.12.0", @@ -165,12 +173,12 @@ } }, "@angular-devkit/schematics": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-9.1.0.tgz", - "integrity": "sha512-cb9PSvskMwWlL54fPfCcpJoyNDWAX6Wo7CzL5qpIB2cJCPLAuyfRUYYrkO77YUST+n2HvypHz0cZ5SNGMfaaBQ==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-9.1.1.tgz", + "integrity": "sha512-6wx2HcvafHvEjEa1tjDzW2hXrOiSE8ALqJUArb3+NoO1BDM42aGcqyPo0ODzKtDk12CgSsFXdNKRpQ5AmpSPtw==", "dev": true, "requires": { - "@angular-devkit/core": "9.1.0", + "@angular-devkit/core": "9.1.1", "ora": "4.0.3", "rxjs": "6.5.4" }, @@ -187,21 +195,21 @@ } }, "@angular/animations": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-9.1.0.tgz", - "integrity": "sha512-o7X3HM+eocoryw3VrDUtG6Wci2KwtzyBFo3KBJXjQ16X6fwdkjTG+hLb7pp2CBFBEJW4tPYEy7cSBmEfMRTqag==" + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-9.1.1.tgz", + "integrity": "sha512-IvKv8sV0ymbzDEX2ZLW+F6nOTQqDYallHexuzRVT9txvNE8TNHyySvLcyC5dTmX9fj9LA72NZ6nFyhxq0LFvtQ==" }, "@angular/cli": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-9.1.0.tgz", - "integrity": "sha512-ofum4gPE/W3fKyzuJrpdHeOS0ZL8x0eYCgsrMyUoFodSpb5LWPqeW+56NgDTpIeny+Trx3pM9dr9QTUVTJ0vYg==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-9.1.1.tgz", + "integrity": "sha512-sjRAV4UF8M5v+2gw+EwCYSgciBZDc05AbNxQt+uUdxdfR1QU9hifWq8WDxfOR6jdDP5YqMtQsNaFNwrUyjJJoQ==", "dev": true, "requires": { - "@angular-devkit/architect": "0.901.0", - "@angular-devkit/core": "9.1.0", - "@angular-devkit/schematics": "9.1.0", - "@schematics/angular": "9.1.0", - "@schematics/update": "0.901.0", + "@angular-devkit/architect": "0.901.1", + "@angular-devkit/core": "9.1.1", + "@angular-devkit/schematics": "9.1.1", + "@schematics/angular": "9.1.1", + "@schematics/update": "0.901.1", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.1", "debug": "4.1.1", @@ -210,7 +218,7 @@ "npm-package-arg": "8.0.1", "npm-pick-manifest": "6.0.0", "open": "7.0.3", - "pacote": "11.1.4", + "pacote": "9.5.12", "read-package-tree": "5.3.1", "rimraf": "3.0.2", "semver": "7.1.3", @@ -234,19 +242,19 @@ } }, "@angular/common": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-9.1.0.tgz", - "integrity": "sha512-6JPLNtMhI03bGTVQJeSwc+dTjV6DtP7M/BAyzIV0InZP1D6XsOh2QahLFIaaN2sSxYA2ClKuwfX1v+rx9AbXQA==" + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-9.1.1.tgz", + "integrity": "sha512-bS13veMs7//YqYjYJ+JI78ylaCyVcdFKZKikd5SZa6+r6fajcyvLnSKqrKypG3O1BeJ8vOG/Pq54P5gWhbR6eA==" }, "@angular/compiler": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.1.0.tgz", - "integrity": "sha512-QHw/JSeTXHiJQ2Ih0EtU7FGsYcOr+0hwZhqwSW3EEn8TtUgA3DS5lXeiDV66f+3DdvNZFPmgiZIvun3ypxn1HA==" + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.1.1.tgz", + "integrity": "sha512-u1IP6IzUgK6lIzrG1cxp96umXgtThyhuFn/KPoyVt7wPxZ6vVR0ZxjM7zycEcrMGzk0nf0nyOKaksJk9sTXTbg==" }, "@angular/compiler-cli": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-9.1.0.tgz", - "integrity": "sha512-xZ8mVPmPporSTtvNA+cbFJQymLzuWfMX6HDDgztZ2eZ5WcQJYloRN4CcYMEzDhCxfV1Zw9Tfc2l14jZD8osi6g==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-9.1.1.tgz", + "integrity": "sha512-2jGp0ck2kkLNMzXUo/3iJkrQqJ7oGXE8h2tksxBsH2ptnhexRYTHZ626t7Np128tduY5JeC7J1Jxz7MUuYsJ2Q==", "dev": true, "requires": { "canonical-path": "1.0.0", @@ -337,9 +345,9 @@ } }, "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -447,35 +455,35 @@ } }, "@angular/core": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.1.0.tgz", - "integrity": "sha512-RVlyegdIAij0P1wLY5ObIdsBAzvmHkHfElnmfiNKhaDftP6U/3zRtaKDu0bq0jvn1WCQ8zXxFQ8AWyKZwyFS+w==" + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.1.1.tgz", + "integrity": "sha512-6lDlUlePafr/392hOvvTZZl6xPHT50U6658sHUAVIr0Un4mJ2MHNHKZtO45bpn3hM4gjFcYRQ7Rpd0umW74iTA==" }, "@angular/forms": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-9.1.0.tgz", - "integrity": "sha512-5GC8HQlPChPV+168zLlm4yj4syA6N9ChSKV0tmzj1zIfMcub1UAOaB9IYaXRHQsjPFh9OuQXwmkzScyAfhEVjA==" + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-9.1.1.tgz", + "integrity": "sha512-NX+LuK8JFisiq3uHCOK6YoN/yIb2R9Ye5mwiOPkuZA3lZLKCnUXqCHZbM8VHy/WdjIxxeUaFMJc38yV8RVoabg==" }, "@angular/language-service": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-9.1.0.tgz", - "integrity": "sha512-2f8ECoXrj40oS1rtIfi+F8T4WPzundcZDs8WMFNBuWYbk14v1S9sTgMEmZyePHGkPjt6IfYiLJKJCvVgrt1nxQ==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-9.1.1.tgz", + "integrity": "sha512-T+/0X2VnmgW/vzynqYTVv29qtebNvrCB/yJqtNIlqXvBjcB8XRRwZPDZvRyl5BiwEPSsJnjdRFNH9krQHxYp+g==", "dev": true }, "@angular/platform-browser": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-9.1.0.tgz", - "integrity": "sha512-OsS/blUjl8ranmDaRADjFAmvnlmwbT6WNU7dVov7FhV0rqesbwaOJ5bR0LSYHYpej7Jaa6oYk0v0XWkaH9LTFg==" + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-9.1.1.tgz", + "integrity": "sha512-tjALKhdAWPErj0euIIdvx/31AHEZ7is7ADsMu+nYn2NY2gcPUuiqq3RCUJVxBYJ2Cclq1nlF0i2rEDKh7TrBKg==" }, "@angular/platform-browser-dynamic": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.1.0.tgz", - "integrity": "sha512-sMtz/poQ3TYaWZzWjrn9apKUZ/WKql2MYCWbpax7pql3GgC9OoTslc7ZEe7/d3ynfFE/CQqWBBOuWGD71Z0LMQ==" + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.1.1.tgz", + "integrity": "sha512-kEox5UOwkRLjGKXLh5o5SYopoAylpKgrXtRrKRKTCMmZTpYSe1bLlXMjpwMAMZ9ZFSTvWp9iX94aT5bJDpLrRQ==" }, "@angular/router": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-9.1.0.tgz", - "integrity": "sha512-cExO1nPnoPFiUJWZ28hTHozPLFoCmqr3xqcM57We0hhKE0esdrO+gRWKRH0EJERukLbU8coPKVhA8daGUpASiQ==" + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-9.1.1.tgz", + "integrity": "sha512-OQ5Ctd+swF7ZNlgUxrkGKk2B4yBFqJm0QCxkM86kFDCKQV/4OButZ+4HPy1HxeozBIAmm2pbQA+YjsAUs0VZcQ==" }, "@babel/code-frame": { "version": "7.8.3", @@ -863,13 +871,14 @@ } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.0.tgz", - "integrity": "sha512-UgqBv6bjq4fDb8uku9f+wcm1J7YxJ5nT7WO/jBr0cl0PLKb7t1O6RNR1kZbjgx2LQtsDI9hwoQVmn0yhXeQyow==", + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.5.tgz", + "integrity": "sha512-VP2oXvAf7KCYTthbUHwBlewbl1Iq059f6seJGsxMizaCdgHIeczOr7FBqELhSqfkIl04Fi8okzWzl63UKbQmmg==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0" + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.9.5" } }, "@babel/plugin-proposal-optional-catch-binding": { @@ -1023,19 +1032,49 @@ } }, "@babel/plugin-transform-classes": { - "version": "7.9.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.2.tgz", - "integrity": "sha512-TC2p3bPzsfvSsqBZo0kJnuelnoK9O3welkUpqSqBQuBF6R5MN2rysopri8kNvtlGIb2jmUO7i15IooAZJjZuMQ==", + "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, "requires": { "@babel/helper-annotate-as-pure": "^7.8.3", "@babel/helper-define-map": "^7.8.3", - "@babel/helper-function-name": "^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" + }, + "dependencies": { + "@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, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.9.5" + } + }, + "@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 + }, + "@babel/types": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", + "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.9.5", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/plugin-transform-computed-properties": { @@ -1048,9 +1087,9 @@ } }, "@babel/plugin-transform-destructuring": { - "version": "7.8.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.8.tgz", - "integrity": "sha512-eRJu4Vs2rmttFCdhPUM3bV0Yo/xPSdPw6ML9KHs/bjB4bLA5HXlbvYXPOD5yASodGod+krjYx21xm1QmL8dCJQ==", + "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, "requires": { "@babel/helper-plugin-utils": "^7.8.3" @@ -1196,9 +1235,9 @@ } }, "@babel/plugin-transform-parameters": { - "version": "7.9.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.3.tgz", - "integrity": "sha512-fzrQFQhp7mIhOzmOtPiKffvCYQSK10NR8t6BBz2yPbeUHb9OLW8RZGtgDRBn8z2hGcwvKDL3vC7ojPTLNxmqEg==", + "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, "requires": { "@babel/helper-get-function-arity": "^7.8.3", @@ -1473,12 +1512,12 @@ } }, "@ngtools/webpack": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-9.1.0.tgz", - "integrity": "sha512-kQ+1N/F+5tuUXiiaoqJwhcOIM0I93EEvF3xwpTLRm91wl2i8R1261LvsD/uQPrgLrZNGR6eFhFF1Izn2PnIjQA==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-9.1.1.tgz", + "integrity": "sha512-4RPlk6aIlYhk9isTvXbMaA2G0LhxOzcZ+2iG7zV9Yj/Vm8+lrRexpQ/kC/Dh0GI/oCtKIkVpUzx5LTozYeTLdQ==", "dev": true, "requires": { - "@angular-devkit/core": "9.1.0", + "@angular-devkit/core": "9.1.1", "enhanced-resolve": "4.1.1", "rxjs": "6.5.4", "webpack-sources": "1.4.3" @@ -1495,87 +1534,28 @@ } } }, - "@npmcli/ci-detect": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-1.2.0.tgz", - "integrity": "sha512-JtktVH7ASBVIWsQTFlFpeOzhBJskvoBCTfeeRhhZy7ybATcUvwiwotZ8j5rkqUUyB69lIy/AvboiiiGBjYBKBA==", - "dev": true - }, - "@npmcli/git": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.0.1.tgz", - "integrity": "sha512-hVatexiBtx71F01Ars38Hr5AFUGmJgHAfQtRlO5fJlnAawRGSXwEFgjB5i3XdUUmElZU/RXy7fefN02dZKxgPw==", - "dev": true, - "requires": { - "@npmcli/promise-spawn": "^1.1.0", - "mkdirp": "^1.0.3", - "npm-pick-manifest": "^6.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^1.1.1", - "unique-filename": "^1.1.1", - "which": "^2.0.2" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.3.tgz", - "integrity": "sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "@npmcli/installed-package-contents": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.5.tgz", - "integrity": "sha512-aKIwguaaqb6ViwSOFytniGvLPb9SMCUm39TgM3SfUo7n0TxUMbwoXfpwyvQ4blm10lzbAwTsvjr7QZ85LvTi4A==", - "dev": true, - "requires": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1", - "read-package-json-fast": "^1.1.1", - "readdir-scoped-modules": "^1.1.0" - } - }, - "@npmcli/promise-spawn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.1.0.tgz", - "integrity": "sha512-FwbuYN9KXBkloLeIR3xRgI8dyOdfK/KzaJlChszNuwmUXD1lHXfLlSeo4n4KrKt2udIK9K9/TzlnyCA3ubM2fA==", - "dev": true, - "requires": { - "infer-owner": "^1.0.4" - } - }, "@schematics/angular": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-9.1.0.tgz", - "integrity": "sha512-qkehaITQ1S1udfnnBY5CXGWnk1iVFI8cZayjLUlRfD5w+6v9if3VIuqPssX96MqvkbjyRu1N214+ieaawzLmuA==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-9.1.1.tgz", + "integrity": "sha512-V0DcDNgHQ2YR+PGZI6+pf/mUNNxt5SusShkZ1PbwIMk/HUQpzEGkLjm3v1Jw9eIZKiuDx615GNU1xDzQ/KyNRQ==", "dev": true, "requires": { - "@angular-devkit/core": "9.1.0", - "@angular-devkit/schematics": "9.1.0" + "@angular-devkit/core": "9.1.1", + "@angular-devkit/schematics": "9.1.1" } }, "@schematics/update": { - "version": "0.901.0", - "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.901.0.tgz", - "integrity": "sha512-u2VESL1dgOSGZK/wcWEz0WcCU/yv764zhzCQerCwUtbV1CISSSDZ6x+prVYDXOdxWBGtDos2MbCF3GEJJI1T+w==", + "version": "0.901.1", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.901.1.tgz", + "integrity": "sha512-g5B8hjXKCbUNLKCkWQxc5r2D9lOQXRTLZJNIqva+l/ck0AML5MpelxkqQId9ZGLfQqfFk/XjdSHRWgcmUs1WnA==", "dev": true, "requires": { - "@angular-devkit/core": "9.1.0", - "@angular-devkit/schematics": "9.1.0", + "@angular-devkit/core": "9.1.1", + "@angular-devkit/schematics": "9.1.1", "@yarnpkg/lockfile": "1.1.0", "ini": "1.3.5", "npm-package-arg": "^8.0.0", - "pacote": "11.1.4", + "pacote": "9.5.12", "rxjs": "6.5.4", "semver": "7.1.3", "semver-intersect": "1.4.0" @@ -1592,12 +1572,6 @@ } } }, - "@tootallnate/once": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.0.0.tgz", - "integrity": "sha512-KYyTT/T6ALPkIRd2Ge080X/BsXvy9O0hcWTtMWkPvwAwF99+vn6Dv4GzrFT/Nn1LePr+FFDbRXXlqmsy9lw2zA==", - "dev": true - }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -1643,10 +1617,9 @@ "dev": true }, "@types/node": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.11.0.tgz", - "integrity": "sha512-uM4mnmsIIPK/yeO+42F2RQhGUIs39K2RFmugcJANppXe6J1nvH87PvzPZYpza7Xhhs8Yn9yIAVdLZ84z61+0xQ==", - "dev": true + "version": "13.11.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.11.1.tgz", + "integrity": "sha512-eWQGP3qtxwL8FGneRrC5DwrJLGN4/dH1clNTuLfN81HCrxVtxRjygDTUoZJ5ASlDEeo0ppYFQjQIlXhtXpOn6g==" }, "@types/q": { "version": "1.5.2", @@ -1879,6 +1852,16 @@ "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", @@ -1908,22 +1891,20 @@ "dev": true }, "agent-base": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz", - "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, "requires": { - "debug": "4" + "es6-promisify": "^5.0.0" } }, "agentkeepalive": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.1.0.tgz", - "integrity": "sha512-CW/n1wxF8RpEuuiq6Vbn9S8m0VSYDMnZESqaJ6F2cWN9fY8rei2qaxweIaRgq+ek8TqfoFIsUjaGNKGGEHElSg==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", "dev": true, "requires": { - "debug": "^4.1.0", - "depd": "^1.1.2", "humanize-ms": "^1.2.1" } }, @@ -2683,28 +2664,6 @@ "isarray": "^1.0.0" } }, - "buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "dev": true, - "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "dev": true - }, - "buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", - "dev": true - }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -2778,9 +2737,9 @@ }, "dependencies": { "mkdirp": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.3.tgz", - "integrity": "sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, "rimraf": { @@ -2860,9 +2819,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001038", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001038.tgz", - "integrity": "sha512-zii9quPo96XfOiRD4TrfYGs+QsGZpb2cGiMAzPjtf/hpFgB6zCPZgJb7I1+EATeMw/o+lG8FyRAnI+CWStHcaQ==", + "version": "1.0.30001040", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001040.tgz", + "integrity": "sha512-Ep0tEPeI5wCvmJNrXjE3etgfI+lkl1fTDU6Y3ZH1mhrjkPlVI9W4pcKbMo+BQLpEWKVYYp2EmYaRsqpPC3k7lQ==", "dev": true }, "canonical-path": { @@ -2991,9 +2950,9 @@ } }, "cli-spinners": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.2.0.tgz", - "integrity": "sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.3.0.tgz", + "integrity": "sha512-Xs2Hf2nzrvJMFKimOR7YR0QwZ8fc0u98kdtwN1eNAZzNQgH3vK2pXzff6GJtKh7S5hoJ87ECiAiZFS2fb5Ii2w==", "dev": true }, "cli-width": { @@ -3141,9 +3100,9 @@ } }, "colors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true }, "combined-stream": { @@ -3439,9 +3398,9 @@ } }, "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -3491,12 +3450,12 @@ "dev": true }, "core-js-compat": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.4.tgz", - "integrity": "sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA==", + "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, "requires": { - "browserslist": "^4.8.3", + "browserslist": "^4.8.5", "semver": "7.0.0" }, "dependencies": { @@ -3826,6 +3785,15 @@ } } }, + "curray": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/curray/-/curray-1.0.7.tgz", + "integrity": "sha512-YBQwAEOdg0/wnmQu7XRzuOFkisEsbcrvc7T2HOUw1sZvreI6YmSDyJCpvyYvYizDtz2yCCnCt/ym29W22UIUOQ==", + "requires": { + "@types/node": "^13.7.0", + "tslib": "^1.10.0" + } + }, "custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -4236,9 +4204,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.391", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.391.tgz", - "integrity": "sha512-WOi6loSnDmfICOqGRrgeK7bZeWDAbGjCptDhI5eyJAqSzWfoeRuOOU1rOTZRL29/9AaxTndZB6Uh8YrxRfZJqw==", + "version": "1.3.402", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.402.tgz", + "integrity": "sha512-gaCDfX7IUH0s3JmBiHCDPrvVcdnTTP1r4WLJc2dHkYYbLmXZ2XHiJCcGQ9Balf91aKTvuCKCyu2JjJYRykoI1w==", "dev": true }, "elliptic": { @@ -4279,7 +4247,6 @@ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", "dev": true, - "optional": true, "requires": { "iconv-lite": "~0.4.13" } @@ -4980,9 +4947,9 @@ } }, "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -5176,6 +5143,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "genfun": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", + "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==", + "dev": true + }, "gensync": { "version": "1.0.0-beta.1", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", @@ -5497,9 +5470,9 @@ "dev": true }, "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "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 }, "http-deceiver": { @@ -5547,14 +5520,30 @@ } }, "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "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, "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } } }, "http-proxy-middleware": { @@ -5587,13 +5576,24 @@ "dev": true }, "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "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, "requires": { - "agent-base": "6", - "debug": "4" + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } } }, "humanize-ms": { @@ -6055,12 +6055,6 @@ "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true }, - "is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", - "dev": true - }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -6182,13 +6176,10 @@ "dev": true }, "isbinaryfile": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", - "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", - "dev": true, - "requires": { - "buffer-alloc": "^1.2.0" - } + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.6.tgz", + "integrity": "sha512-ORrEy+SNVqUhrCaal4hA4fBzhggQQ+BaLntyPOdoEiwlKZW9BZiJXjg3RMiruE4tPEI3pyVPpySHQF/dKWperg==", + "dev": true }, "isexe": { "version": "2.0.0", @@ -6478,12 +6469,6 @@ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, - "json-parse-even-better-errors": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.2.0.tgz", - "integrity": "sha512-2tLgY7LRNZ9Hd6gmCuBG5/OjRHQpSgJQqJoYyLLOhUgn8LdOYrjaZLcxkWnDads+AD/haWWioPNziXQcgvQJ/g==", - "dev": true - }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -6509,9 +6494,9 @@ "dev": true }, "json5": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.2.tgz", - "integrity": "sha512-MoUOQ4WdiN3yxhm7NEVJSJrieAo5hNSLQ5sj05OTRHPL9HOBy8u4Bu88jsC1jvqAdN+E1bJmsUcZH+1HQxliqQ==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", "dev": true, "requires": { "minimist": "^1.2.5" @@ -6557,12 +6542,11 @@ } }, "karma": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/karma/-/karma-4.4.1.tgz", - "integrity": "sha512-L5SIaXEYqzrh6b1wqYC42tNsFMx2PWuxky84pK9coK09MvmL7mxii3G3bZBh/0rvD27lqDd0le9jyhzvwif73A==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/karma/-/karma-5.0.1.tgz", + "integrity": "sha512-xrDGtZ0mykEQjx1BUHOP1ITi39MDsCGocmSvLJWHxUQpxuKwxk3ZUrC6HI2VWh1plLC6+7cA3B19m12yzO/FRw==", "dev": true, "requires": { - "bluebird": "^3.3.0", "body-parser": "^1.16.1", "braces": "^3.0.2", "chokidar": "^3.0.0", @@ -6574,28 +6558,136 @@ "glob": "^7.1.1", "graceful-fs": "^4.1.2", "http-proxy": "^1.13.0", - "isbinaryfile": "^3.0.0", + "isbinaryfile": "^4.0.2", "lodash": "^4.17.14", "log4js": "^4.0.0", "mime": "^2.3.1", "minimatch": "^3.0.2", - "optimist": "^0.6.1", "qjobs": "^1.1.4", "range-parser": "^1.2.0", "rimraf": "^2.6.0", - "safe-buffer": "^5.0.1", "socket.io": "2.1.1", "source-map": "^0.6.1", "tmp": "0.0.33", - "useragent": "2.3.0" + "ua-parser-js": "0.7.21", + "yargs": "^15.3.1" }, "dependencies": { + "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 + }, + "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, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "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 + }, + "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 + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, "mime": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", "dev": true }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-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 + }, + "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 + }, + "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 + }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -6610,6 +6702,66 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true + }, + "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, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "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, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "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, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "yargs": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", + "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", + "dev": true, + "requires": { + "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" + } + }, + "yargs-parser": { + "version": "18.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.2.tgz", + "integrity": "sha512-hlIPNR3IzC1YuL1c2UwwDKpXlNFBqD1Fswwh1khz5+d8Cq/8yc/Mn0i+rQXduu8hcrFKvO7Eryk+09NecTQAAQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } } } }, @@ -6910,26 +7062,65 @@ "dev": true }, "make-fetch-happen": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.4.tgz", - "integrity": "sha512-hIFoqGq1db0QMiy/Atr/pI1Rs4rDV+ZdGSey2SQyF3KK3u1z4aj9mS5UdNnZkdQpA+H3pGn0J3KlEwsi2x4EqA==", + "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, "requires": { - "agentkeepalive": "^4.1.0", - "cacache": "^15.0.0", - "http-cache-semantics": "^4.0.4", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", + "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", - "minipass": "^3.0.0", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.1.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", "promise-retry": "^1.1.1", - "socks-proxy-agent": "^5.0.0", - "ssri": "^8.0.0" + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + }, + "dependencies": { + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "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" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "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, + "requires": { + "figgy-pudding": "^3.5.1" + } + } } }, "mamacro": { @@ -7285,19 +7476,6 @@ "minipass": "^3.0.0" } }, - "minipass-fetch": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.2.1.tgz", - "integrity": "sha512-ssHt0dkljEDaKmTgQ04DQgx2ag6G2gMPxA5hpcsoeTbfDgRf2fC2gNSRc6kISjD7ckCpHwwQvXxuTBK8402fXg==", - "dev": true, - "requires": { - "encoding": "^0.1.12", - "minipass": "^3.1.0", - "minipass-pipeline": "^1.2.2", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - } - }, "minipass-flush": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", @@ -7307,16 +7485,6 @@ "minipass": "^3.0.0" } }, - "minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", - "dev": true, - "requires": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, "minipass-pipeline": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.2.tgz", @@ -7326,15 +7494,6 @@ "minipass": "^3.0.0" } }, - "minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, "minizlib": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.0.tgz", @@ -7491,6 +7650,17 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "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, + "requires": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + } + }, "node-forge": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", @@ -7622,14 +7792,13 @@ } }, "npm-packlist": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.1.1.tgz", - "integrity": "sha512-95TSDvGwujIhqfSpIiRRLodEF+y6mJMopuZdahoGzqtRDFZXGav46S0p6ngeWaiAkb5R72w6eVARhzej0HvZeQ==", + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", "dev": true, "requires": { - "glob": "^7.1.6", - "ignore-walk": "^3.0.3", - "npm-bundled": "^1.1.1", + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", "npm-normalize-package-bin": "^1.0.1" } }, @@ -7645,19 +7814,50 @@ } }, "npm-registry-fetch": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-8.0.0.tgz", - "integrity": "sha512-975WwLvZjX97y9UWWQ8nAyr7bw02s9xKPHqvEm5T900LQsB1HXb8Gb9ebYtCBLSX+K8gSOrO5KS/9yV/naLZmQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.3.tgz", + "integrity": "sha512-WGvUx0lkKFhu9MbiGFuT9nG2NpfQ+4dCJwRwwtK2HK5izJEvwDxMeUyqbuMS7N/OkpVCqDorV6rO5E4V9F8lJw==", "dev": true, "requires": { - "@npmcli/ci-detect": "^1.0.0", + "JSONStream": "^1.3.4", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", "lru-cache": "^5.1.1", - "make-fetch-happen": "^8.0.2", - "minipass": "^3.0.0", - "minipass-fetch": "^1.1.2", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" + "make-fetch-happen": "^5.0.0", + "npm-package-arg": "^6.1.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "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 + }, + "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, + "requires": { + "hosted-git-info": "^2.7.1", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "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 + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, "npm-run-path": { @@ -7991,6 +8191,12 @@ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", "dev": true }, + "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 + }, "os-locale": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", @@ -8008,6 +8214,16 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", @@ -8069,42 +8285,123 @@ "dev": true }, "pacote": { - "version": "11.1.4", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.1.4.tgz", - "integrity": "sha512-eUGJvSSpWFZKn3z8gig/HgnBmUl6gIWByIIaHzSyEr3tOWX0w8tFEADXtpu8HGv5E0ShCeTP6enRq8iHKCHSvw==", + "version": "9.5.12", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.12.tgz", + "integrity": "sha512-BUIj/4kKbwWg4RtnBncXPJd15piFSVNpTzY0rysSr3VnMowTYgkGKcaHrbReepAkjTr8lH2CVWRi58Spg2CicQ==", "dev": true, "requires": { - "@npmcli/git": "^2.0.1", - "@npmcli/installed-package-contents": "^1.0.5", - "@npmcli/promise-spawn": "^1.1.0", - "cacache": "^15.0.0", - "chownr": "^1.1.4", - "fs-minipass": "^2.1.0", + "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", - "minipass": "^3.0.1", - "minipass-fetch": "^1.2.1", - "mkdirp": "^1.0.3", - "npm-package-arg": "^8.0.1", - "npm-packlist": "^2.1.0", - "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^8.0.0", + "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", - "read-package-json-fast": "^1.1.3", - "rimraf": "^2.7.1", - "semver": "^7.1.3", - "ssri": "^8.0.0", - "tar": "^6.0.1", - "which": "^2.0.2" + "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" }, "dependencies": { - "mkdirp": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.3.tgz", - "integrity": "sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==", + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "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" + } + }, + "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, + "requires": { + "minipass": "^2.6.0" + } + }, + "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 }, + "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, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "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, + "requires": { + "hosted-git-info": "^2.7.1", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "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, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -8114,14 +8411,41 @@ "glob": "^7.1.3" } }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "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, "requires": { - "isexe": "^2.0.0" + "figgy-pudding": "^3.5.1" } + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "dev": true, + "requires": { + "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" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true } } }, @@ -8342,9 +8666,9 @@ } }, "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -9045,6 +9369,15 @@ } } }, + "protoduck": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", + "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", + "dev": true, + "requires": { + "genfun": "^5.0.0" + } + }, "protractor": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.4.3.tgz", @@ -9231,12 +9564,6 @@ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", "dev": true }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -9449,16 +9776,6 @@ "npm-normalize-package-bin": "^1.0.0" } }, - "read-package-json-fast": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-1.1.3.tgz", - "integrity": "sha512-MmFqiyfCXV2Dmm4jH24DEGhxdkUDFivJQj4oPZQPOKywxR7HWBE6WnMWDAapfFHi3wm1b+mhR+XHlUH0CL8axg==", - "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.0.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, "read-package-tree": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", @@ -10542,14 +10859,24 @@ } }, "socks-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz", - "integrity": "sha512-lEpa1zsWCChxiynk+lCycKuC502RxDWLKJZoIhnxrWNjLSDGYRFflHA1/228VkRcnv9TIb8w98derGbpKxJRgA==", + "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, "requires": { - "agent-base": "6", - "debug": "4", - "socks": "^2.3.3" + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "dependencies": { + "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, + "requires": { + "es6-promisify": "^5.0.0" + } + } } }, "sort-keys": { @@ -10681,9 +11008,9 @@ "dev": true }, "spdy": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.1.tgz", - "integrity": "sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, "requires": { "debug": "^4.1.0", @@ -10911,9 +11238,9 @@ } }, "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==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", "dev": true, "requires": { "define-properties": "^1.1.3", @@ -10943,9 +11270,9 @@ } }, "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==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", "dev": true, "requires": { "define-properties": "^1.1.3", @@ -11167,17 +11494,17 @@ }, "dependencies": { "mkdirp": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.3.tgz", - "integrity": "sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true } } }, "terser": { - "version": "4.6.7", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.7.tgz", - "integrity": "sha512-fmr7M1f7DBly5cX2+rFDvmGBAaaZyPrHYK4mMdHEDAdNTqXSZgSOfqsfGq2HqPGT/1V0foZZuCZFx8CHKgAk3g==", + "version": "4.6.10", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.10.tgz", + "integrity": "sha512-qbF/3UOo11Hggsbsqm2hPa6+L4w7bkr+09FNseEe8xrcVD3APGLFqE+Oz1ZKAxjYnFsj80rLOfgAtJ0LNJjtTA==", "dev": true, "requires": { "commander": "^2.20.0", @@ -11237,9 +11564,9 @@ } }, "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -11510,6 +11837,12 @@ "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", "dev": true }, + "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 + }, "ultron": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", @@ -11721,34 +12054,6 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, - "useragent": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", - "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", - "dev": true, - "requires": { - "lru-cache": "4.1.x", - "tmp": "0.0.x" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } - }, "util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", @@ -13784,9 +14089,9 @@ } }, "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" diff --git a/client/package.json b/client/package.json index f966442..585c167 100644 --- a/client/package.json +++ b/client/package.json @@ -11,33 +11,34 @@ }, "private": true, "dependencies": { - "@angular/animations": "~9.1.0", - "@angular/common": "~9.1.0", - "@angular/compiler": "~9.1.0", - "@angular/core": "~9.1.0", - "@angular/forms": "~9.1.0", - "@angular/platform-browser": "~9.1.0", - "@angular/platform-browser-dynamic": "~9.1.0", - "@angular/router": "~9.1.0", + "@angular/animations": "~9.1.1", + "@angular/common": "~9.1.1", + "@angular/compiler": "~9.1.1", + "@angular/core": "~9.1.1", + "@angular/forms": "~9.1.1", + "@angular/platform-browser": "~9.1.1", + "@angular/platform-browser-dynamic": "~9.1.1", + "@angular/router": "~9.1.1", "@fortawesome/fontawesome-free": "^5.13.0", "bulma": "^0.8.1", + "curray": "^1.0.7", "ngx-filesize": "^2.0.13", "rxjs": "~6.5.5", "tslib": "^1.11.1", "zone.js": "~0.10.3" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.901.0", - "@angular/cli": "~9.1.0", - "@angular/compiler-cli": "~9.1.0", - "@angular/language-service": "~9.1.0", - "@types/node": "^13.11.0", + "@angular-devkit/build-angular": "~0.901.1", + "@angular/cli": "~9.1.1", + "@angular/compiler-cli": "~9.1.1", + "@angular/language-service": "~9.1.1", + "@types/node": "^13.11.1", "@types/jasmine": "~3.5.10", "@types/jasminewd2": "~2.0.8", "codelyzer": "^5.2.2", "jasmine-core": "~3.5.0", "jasmine-spec-reporter": "~5.0.1", - "karma": "~4.4.1", + "karma": "~5.0.1", "karma-chrome-launcher": "~3.1.0", "karma-coverage-istanbul-reporter": "~2.1.1", "karma-jasmine": "~3.1.1", diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index 02839f2..6390cb1 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts @@ -17,6 +17,9 @@ import { TorrentStatusPipe } from './torrent-status.pipe'; import { FileStatusPipe } from './file-status.pipe'; import { LoginComponent } from './login/login.component'; import { AuthInterceptor } from './auth.interceptor'; +import { curray } from 'curray'; + +curray(); @NgModule({ declarations: [ diff --git a/client/src/app/file-status.pipe.ts b/client/src/app/file-status.pipe.ts index f81a746..16888d4 100644 --- a/client/src/app/file-status.pipe.ts +++ b/client/src/app/file-status.pipe.ts @@ -15,7 +15,11 @@ export class FileStatusPipe implements PipeTransform { } if (value.download.status === DownloadStatus.Downloading) { - return `${value.download.progress}%`; + const progress = ( + (value.download.bytesDownloaded / value.download.bytesSize) * + 100 + ).toFixed(2); + return `${progress || 0}%`; } if (value.download.status === DownloadStatus.Finished) { diff --git a/client/src/app/models/download.model.ts b/client/src/app/models/download.model.ts index 284ac5d..8bfcca3 100644 --- a/client/src/app/models/download.model.ts +++ b/client/src/app/models/download.model.ts @@ -9,13 +9,16 @@ export class Download { public status: DownloadStatus; - public progress: number; + public bytesDownloaded: number; + + public bytesSize: number; public speed: number; } export enum DownloadStatus { PendingDownload = 0, - Downloading, - Finished, + Downloading = 1, + Unpacking = 2, + Finished = 3, } diff --git a/client/src/app/models/torrent.model.ts b/client/src/app/models/torrent.model.ts index 50d7ff4..d065b29 100644 --- a/client/src/app/models/torrent.model.ts +++ b/client/src/app/models/torrent.model.ts @@ -19,7 +19,6 @@ export class Torrent { files: TorrentFile[]; downloads: Download[]; - activeDownload: Download; } export class TorrentFile { @@ -33,9 +32,10 @@ export class TorrentFile { export enum TorrentStatus { RealDebrid = 0, - WaitingForDownload, - Downloading, - Finished, + WaitingForDownload = 1, + DownloadQueued = 2, + Downloading = 3, + Finished = 4, Error = 99, } diff --git a/client/src/app/torrent-row/torrent-row.component.html b/client/src/app/torrent-row/torrent-row.component.html index 25a8523..07ceed8 100644 --- a/client/src/app/torrent-row/torrent-row.component.html +++ b/client/src/app/torrent-row/torrent-row.component.html @@ -24,4 +24,7 @@ > + + + diff --git a/client/src/app/torrent-status.pipe.ts b/client/src/app/torrent-status.pipe.ts index dfe4c9e..b98fd81 100644 --- a/client/src/app/torrent-status.pipe.ts +++ b/client/src/app/torrent-status.pipe.ts @@ -1,6 +1,7 @@ import { Pipe, PipeTransform } from '@angular/core'; import { Torrent, TorrentStatus } from './models/torrent.model'; import { FileSizePipe } from 'ngx-filesize'; +import { DownloadStatus } from './models/download.model'; @Pipe({ name: 'status', @@ -9,23 +10,59 @@ export class TorrentStatusPipe implements PipeTransform { constructor(private pipe: FileSizePipe) {} transform(torrent: Torrent): string { - switch (torrent.status) { - case TorrentStatus.RealDebrid: { - const speed = this.pipe.transform(torrent.rdSpeed, 'filesize'); - return `Downloading from RD (${torrent.rdProgress}% - ${speed}/s)`; + if (torrent.downloads && torrent.downloads.length > 0) { + const allFinished = torrent.downloads.all( + (m) => m.status === DownloadStatus.Finished + ); + if (allFinished) { + return 'Finished'; } + + const downloading = torrent.downloads.where( + (m) => m.status === DownloadStatus.Downloading + ); + const unpacking = torrent.downloads.where( + (m) => m.status === DownloadStatus.Unpacking + ); + + if (downloading.length > 0) { + const allBytesDownloaded = torrent.downloads.sum( + (m) => m.bytesDownloaded + ); + const allBytesSize = torrent.downloads.sum((m) => m.bytesSize); + + if (allBytesSize > 0) { + const progress = ((allBytesDownloaded / allBytesSize) * 100).toFixed( + 2 + ); + + const allSpeeds = + downloading.sum((m) => m.speed) / downloading.length; + const speed = this.pipe.transform(allSpeeds, 'filesize'); + + return `Downloading (${progress || 0}% - ${speed}/s)`; + } + + return `Preparing download`; + } + + if (unpacking.length > 0) { + return `Unpacking`; + } + + return 'Pending download'; + } + + switch (torrent.status) { + case TorrentStatus.RealDebrid: + const speed = this.pipe.transform(torrent.rdSpeed, 'filesize'); + return `Torrent downloading (${torrent.rdProgress}% - ${speed}/s)`; case TorrentStatus.WaitingForDownload: return `Waiting to download`; - case TorrentStatus.Downloading: { - if (torrent.activeDownload != null) { - const speed = this.pipe.transform( - torrent.activeDownload.speed, - 'filesize' - ); - return `Downloading (${torrent.activeDownload.progress}% - ${speed}/s)`; - } + case TorrentStatus.DownloadQueued: + return `Download queued`; + case TorrentStatus.Downloading: return `Downloading`; - } case TorrentStatus.Finished: return `Finished`; case TorrentStatus.Error: diff --git a/client/src/app/torrent-table/torrent-table.component.html b/client/src/app/torrent-table/torrent-table.component.html index 211eb04..be60154 100644 --- a/client/src/app/torrent-table/torrent-table.component.html +++ b/client/src/app/torrent-table/torrent-table.component.html @@ -1,3 +1,7 @@ +
+ An error has occured: {{ error }}
+ Please refresh the screen after fixing this error. +
diff --git a/client/src/app/torrent-table/torrent-table.component.ts b/client/src/app/torrent-table/torrent-table.component.ts index 85eac99..239e949 100644 --- a/client/src/app/torrent-table/torrent-table.component.ts +++ b/client/src/app/torrent-table/torrent-table.component.ts @@ -16,7 +16,7 @@ import { DownloadStatus } from '../models/download.model'; }) export class TorrentTableComponent implements OnInit, OnDestroy { public torrents: Torrent[] = []; - + public error: string; public showFiles: { [key: string]: boolean } = {}; private timer: any; @@ -25,18 +25,15 @@ export class TorrentTableComponent implements OnInit, OnDestroy { ngOnInit(): void { this.timer = setInterval(() => { - this.torrentService.getList().subscribe((result) => { - this.torrents = result; - - this.torrents.forEach((torrent) => { - const activeDownloads = torrent.downloads.filter( - (m) => m.status === DownloadStatus.Downloading - ); - if (activeDownloads.length > 0) { - torrent.activeDownload = activeDownloads[0]; - } - }); - }); + this.torrentService.getList().subscribe( + (result) => { + this.torrents = result; + }, + (err) => { + this.error = err.error; + clearInterval(this.timer); + } + ); }, 1000); } diff --git a/client/tslint.json b/client/tslint.json index d92ff5d..41c5486 100644 --- a/client/tslint.json +++ b/client/tslint.json @@ -2,10 +2,7 @@ "extends": "tslint:recommended", "rules": { "align": { - "options": [ - "parameters", - "statements" - ] + "options": ["parameters", "statements"] }, "array-type": false, "arrow-return-shorthand": true, @@ -16,34 +13,16 @@ "component-class-suffix": true, "contextual-lifecycle": true, "directive-class-suffix": true, - "directive-selector": [ - true, - "attribute", - "app", - "camelCase" - ], - "component-selector": [ - true, - "element", - "app", - "kebab-case" - ], + "directive-selector": [true, "attribute", "app", "camelCase"], + "component-selector": [true, "element", "app", "kebab-case"], "eofline": true, - "import-blacklist": [ - true, - "rxjs/Rx" - ], + "import-blacklist": [true, "rxjs/Rx"], "import-spacing": true, "indent": { - "options": [ - "spaces" - ] + "options": ["spaces"] }, "max-classes-per-file": false, - "max-line-length": [ - true, - 140 - ], + "max-line-length": [true, 140], "member-ordering": [ true, { @@ -55,35 +34,17 @@ ] } ], - "no-console": [ - true, - "debug", - "info", - "time", - "timeEnd", - "trace" - ], + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], "no-empty": false, - "no-inferrable-types": [ - true, - "ignore-params" - ], + "no-inferrable-types": [true, "ignore-params"], "no-non-null-assertion": true, "no-redundant-jsdoc": true, "no-switch-case-fall-through": true, "no-var-requires": false, - "object-literal-key-quotes": [ - true, - "as-needed" - ], - "quotemark": [ - true, - "single" - ], + "object-literal-key-quotes": [true, "as-needed"], + "quotemark": [true, "single"], "semicolon": { - "options": [ - "always" - ] + "options": ["always"] }, "space-before-function-paren": { "options": { @@ -113,11 +74,7 @@ ] }, "variable-name": { - "options": [ - "ban-keywords", - "check-format", - "allow-pascal-case" - ] + "options": ["ban-keywords", "check-format", "allow-pascal-case"] }, "whitespace": { "options": [ @@ -142,7 +99,5 @@ "use-lifecycle-interface": true, "use-pipe-transform-interface": true }, - "rulesDirectory": [ - "codelyzer" - ] -} \ No newline at end of file + "rulesDirectory": ["codelyzer"] +} diff --git a/server/RdtClient.Data/Data/DownloadData.cs b/server/RdtClient.Data/Data/DownloadData.cs index bd5cddf..ef7c1ad 100644 --- a/server/RdtClient.Data/Data/DownloadData.cs +++ b/server/RdtClient.Data/Data/DownloadData.cs @@ -11,6 +11,7 @@ namespace RdtClient.Data.Data public interface IDownloadData { Task> Get(); + Task> GetForTorrent(Guid torrentId); Task Add(Guid torrentId, String link); Task UpdateStatus(Guid downloadId, DownloadStatus status); Task DeleteForTorrent(Guid torrentId); @@ -33,6 +34,14 @@ namespace RdtClient.Data.Data .ToListAsync(); } + public async Task> GetForTorrent(Guid torrentId) + { + return await _dataContext.Downloads + .AsNoTracking() + .Where(m => m.TorrentId == torrentId) + .ToListAsync(); + } + public async Task Add(Guid torrentId, String link) { var download = new Download diff --git a/server/RdtClient.Data/Data/TorrentData.cs b/server/RdtClient.Data/Data/TorrentData.cs index 0db0d9f..6932a28 100644 --- a/server/RdtClient.Data/Data/TorrentData.cs +++ b/server/RdtClient.Data/Data/TorrentData.cs @@ -101,8 +101,6 @@ namespace RdtClient.Data.Data { var dbTorrent = await _dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrent.TorrentId); - dbTorrent.Status = torrent.Status; - dbTorrent.RdName = torrent.RdName; dbTorrent.RdSize = torrent.RdSize; dbTorrent.RdHost = torrent.RdHost; @@ -114,6 +112,11 @@ namespace RdtClient.Data.Data dbTorrent.RdSpeed = torrent.RdSpeed; dbTorrent.RdSeeders = torrent.RdSeeders; + if (torrent.Files != null) + { + dbTorrent.RdFiles = torrent.RdFiles; + } + await _dataContext.SaveChangesAsync(); } diff --git a/server/RdtClient.Data/Enums/TorrentStatus.cs b/server/RdtClient.Data/Enums/TorrentStatus.cs index f89f7cf..bac9dae 100644 --- a/server/RdtClient.Data/Enums/TorrentStatus.cs +++ b/server/RdtClient.Data/Enums/TorrentStatus.cs @@ -3,9 +3,10 @@ public enum TorrentStatus { RealDebrid = 0, - WaitingForDownload, - Downloading, - Finished, + WaitingForDownload = 1, + DownloadQueued = 2, + Downloading = 3, + Finished = 4, Error = 99 } diff --git a/server/RdtClient.Data/Migrations/20200407174750_Initial.Designer.cs b/server/RdtClient.Data/Migrations/20200408224831_Initial.Designer.cs similarity index 98% rename from server/RdtClient.Data/Migrations/20200407174750_Initial.Designer.cs rename to server/RdtClient.Data/Migrations/20200408224831_Initial.Designer.cs index 47df5d9..cbc165d 100644 --- a/server/RdtClient.Data/Migrations/20200407174750_Initial.Designer.cs +++ b/server/RdtClient.Data/Migrations/20200408224831_Initial.Designer.cs @@ -9,7 +9,7 @@ using RdtClient.Data.Data; namespace RdtClient.Data.Migrations { [DbContext(typeof(DataContext))] - [Migration("20200407174750_Initial")] + [Migration("20200408224831_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -277,6 +277,12 @@ namespace RdtClient.Data.Migrations .ValueGeneratedOnAdd() .HasColumnType("TEXT"); + b.Property("AutoDelete") + .HasColumnType("INTEGER"); + + b.Property("AutoDownload") + .HasColumnType("INTEGER"); + b.Property("Category") .HasColumnType("TEXT"); diff --git a/server/RdtClient.Data/Migrations/20200407174750_Initial.cs b/server/RdtClient.Data/Migrations/20200408224831_Initial.cs similarity index 98% rename from server/RdtClient.Data/Migrations/20200407174750_Initial.cs rename to server/RdtClient.Data/Migrations/20200408224831_Initial.cs index f6f2ff1..25aec33 100644 --- a/server/RdtClient.Data/Migrations/20200407174750_Initial.cs +++ b/server/RdtClient.Data/Migrations/20200408224831_Initial.cs @@ -66,6 +66,8 @@ namespace RdtClient.Data.Migrations TorrentId = table.Column(nullable: false), Hash = table.Column(nullable: true), Category = table.Column(nullable: true), + AutoDownload = table.Column(nullable: false), + AutoDelete = table.Column(nullable: false), Status = table.Column(nullable: false), RdId = table.Column(nullable: true), RdName = table.Column(nullable: true), diff --git a/server/RdtClient.Data/Migrations/DataContextModelSnapshot.cs b/server/RdtClient.Data/Migrations/DataContextModelSnapshot.cs index 0e6007b..2ddd0bd 100644 --- a/server/RdtClient.Data/Migrations/DataContextModelSnapshot.cs +++ b/server/RdtClient.Data/Migrations/DataContextModelSnapshot.cs @@ -275,6 +275,12 @@ namespace RdtClient.Data.Migrations .ValueGeneratedOnAdd() .HasColumnType("TEXT"); + b.Property("AutoDelete") + .HasColumnType("INTEGER"); + + b.Property("AutoDownload") + .HasColumnType("INTEGER"); + b.Property("Category") .HasColumnType("TEXT"); diff --git a/server/RdtClient.Data/Models/Data/Download.cs b/server/RdtClient.Data/Models/Data/Download.cs index 89f7938..462705a 100644 --- a/server/RdtClient.Data/Models/Data/Download.cs +++ b/server/RdtClient.Data/Models/Data/Download.cs @@ -22,15 +22,12 @@ namespace RdtClient.Data.Models.Data public Torrent Torrent { get; set; } [NotMapped] - public Int32 Progress { get; set; } + public Int64 BytesSize { get; set; } + + [NotMapped] + public Int64 BytesDownloaded { get; set; } [NotMapped] public Int64 Speed { get; set; } - - [NotMapped] - public DateTime NextUpdate { get; set; } - - [NotMapped] - public Int64 BytesLastUpdate { get; set; } } } diff --git a/server/RdtClient.Data/Models/Data/Torrent.cs b/server/RdtClient.Data/Models/Data/Torrent.cs index 0b82aad..e313540 100644 --- a/server/RdtClient.Data/Models/Data/Torrent.cs +++ b/server/RdtClient.Data/Models/Data/Torrent.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Newtonsoft.Json; -using RDNET.Models; +using RDNET; using RdtClient.Data.Enums; namespace RdtClient.Data.Models.Data @@ -17,6 +17,10 @@ namespace RdtClient.Data.Models.Data public String Category { get; set; } + public Boolean AutoDownload { get; set; } + + public Boolean AutoDelete { get; set; } + public TorrentStatus Status { get; set; } [InverseProperty("Torrent")] diff --git a/server/RdtClient.Data/RdtClient.Data.csproj b/server/RdtClient.Data/RdtClient.Data.csproj index 883337a..3ef9dec 100644 --- a/server/RdtClient.Data/RdtClient.Data.csproj +++ b/server/RdtClient.Data/RdtClient.Data.csproj @@ -4,31 +4,6 @@ netcoreapp3.1 - - - - - - - - - - - - - - - - - - - - - - - - - @@ -39,6 +14,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/server/RdtClient.Service/DiConfig.cs b/server/RdtClient.Service/DiConfig.cs index 8216562..7192a09 100644 --- a/server/RdtClient.Service/DiConfig.cs +++ b/server/RdtClient.Service/DiConfig.cs @@ -10,9 +10,10 @@ namespace RdtClient.Service services.AddScoped(); services.AddScoped(); services.AddScoped(); - services.AddScoped(); services.AddScoped(); services.AddScoped(); + + services.AddHostedService(); } } } \ No newline at end of file diff --git a/server/RdtClient.Service/RdtClient.Service.csproj b/server/RdtClient.Service/RdtClient.Service.csproj index ed62c6d..dfd1577 100644 --- a/server/RdtClient.Service/RdtClient.Service.csproj +++ b/server/RdtClient.Service/RdtClient.Service.csproj @@ -6,9 +6,9 @@ - + @@ -16,10 +16,4 @@ - - - ..\libs\RDNET.dll - - - diff --git a/server/RdtClient.Service/Services/DownloadManager.cs b/server/RdtClient.Service/Services/DownloadManager.cs index 985a28c..96697ff 100644 --- a/server/RdtClient.Service/Services/DownloadManager.cs +++ b/server/RdtClient.Service/Services/DownloadManager.cs @@ -1,12 +1,8 @@ using System; -using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using RdtClient.Data.Data; using RdtClient.Data.Enums; using RdtClient.Data.Models.Data; using SharpCompress.Common; @@ -14,32 +10,37 @@ using SharpCompress.Readers; namespace RdtClient.Service.Services { - public static class DownloadManager + public class DownloadManager { - public static readonly Dictionary ActiveDownloads = new Dictionary(); + public DownloadStatus? NewStatus { get; set; } + public Download Download { get; set; } + public Int64 Speed { get; private set; } + public Int64 BytesDownloaded { get; private set; } + public Int64 BytesSize { get; private set; } - static DownloadManager() + private DateTime _nextUpdate; + private Int64 _bytesLastUpdate; + + public DownloadManager() { ServicePointManager.Expect100Continue = false; ServicePointManager.DefaultConnectionLimit = 100; ServicePointManager.MaxServicePointIdleTime = 1000; } - public static async Task Download(Download download, String destinationFolderPath) + private DownloadManager ActiveDownload => TaskRunner.ActiveDownloads[Download.DownloadId]; + + public async Task Start(String destinationFolderPath) { - await UpdateStatus(download.DownloadId, DownloadStatus.Downloading, TorrentStatus.Downloading); + ActiveDownload.NewStatus = DownloadStatus.Downloading; + ActiveDownload.BytesDownloaded = 0; + ActiveDownload.BytesSize = 0; + ActiveDownload.Speed = 0; + + _bytesLastUpdate = 0; + _nextUpdate = DateTime.UtcNow.AddSeconds(1); - if (!ActiveDownloads.TryAdd(download.DownloadId, download)) - { - return; - } - - download.Progress = 0; - download.BytesLastUpdate = 0; - download.NextUpdate = DateTime.UtcNow.AddSeconds(1); - download.Speed = 0; - - var fileUrl = download.Link; + var fileUrl = Download.Link; var uri = new Uri(fileUrl); var filePath = Path.Combine(destinationFolderPath, uri.Segments.Last()); @@ -77,13 +78,15 @@ namespace RdtClient.Service.Services { fileStream.Write(buffer, 0, read); - ActiveDownloads[download.DownloadId].Progress = (Int32) (fileStream.Length * 100 / responseLength); + ActiveDownload.BytesDownloaded = fileStream.Length; + ActiveDownload.BytesSize = responseLength; - if (DateTime.UtcNow > ActiveDownloads[download.DownloadId].NextUpdate) + if (DateTime.UtcNow > _nextUpdate) { - ActiveDownloads[download.DownloadId].Speed = fileStream.Length - ActiveDownloads[download.DownloadId].BytesLastUpdate; - ActiveDownloads[download.DownloadId].NextUpdate = DateTime.UtcNow.AddSeconds(1); - ActiveDownloads[download.DownloadId].BytesLastUpdate = fileStream.Length; + ActiveDownload.Speed = fileStream.Length - _bytesLastUpdate; + + _nextUpdate = DateTime.UtcNow.AddSeconds(1); + _bytesLastUpdate = fileStream.Length; } } else @@ -93,13 +96,14 @@ namespace RdtClient.Service.Services } } - ActiveDownloads[download.DownloadId].Speed = 0; + ActiveDownload.Speed = 0; + ActiveDownload.BytesDownloaded = ActiveDownload.BytesSize; try { if (filePath.EndsWith(".rar")) { - await UpdateStatus(download.DownloadId, DownloadStatus.Unpacking, TorrentStatus.Downloading); + ActiveDownload.NewStatus = DownloadStatus.Unpacking; await using (Stream stream = File.OpenRead(filePath)) { @@ -141,43 +145,7 @@ namespace RdtClient.Service.Services // ignored } - await UpdateStatus(download.DownloadId, DownloadStatus.Finished, TorrentStatus.Finished); - - ActiveDownloads.Remove(download.DownloadId); - } - - private static async Task UpdateStatus(Guid downloadId, DownloadStatus downloadStatus, TorrentStatus torrentStatus) - { - await using var context = new DataContext(); - - var download = await context.Downloads.FirstOrDefaultAsync(m => m.DownloadId == downloadId); - - download.Status = downloadStatus; - - await context.SaveChangesAsync(); - - var torrent = await context.Torrents.FirstOrDefaultAsync(m => m.TorrentId == download.TorrentId); - - if (torrentStatus == TorrentStatus.Finished) - { - var allDownloads = await context.Downloads.Where(m => m.TorrentId == download.TorrentId) - .ToListAsync(); - - if (allDownloads.All(m => m.Status == DownloadStatus.Finished)) - { - torrent.Status = TorrentStatus.Finished; - } - else - { - torrent.Status = TorrentStatus.Downloading; - } - } - else - { - torrent.Status = torrentStatus; - } - - await context.SaveChangesAsync(); + ActiveDownload.NewStatus = DownloadStatus.Finished; } } } \ No newline at end of file diff --git a/server/RdtClient.Service/Services/Downloads.cs b/server/RdtClient.Service/Services/Downloads.cs index b407012..803c78c 100644 --- a/server/RdtClient.Service/Services/Downloads.cs +++ b/server/RdtClient.Service/Services/Downloads.cs @@ -10,6 +10,7 @@ namespace RdtClient.Service.Services public interface IDownloads { Task> Get(); + Task> GetForTorrent(Guid torrentId); Task Add(Guid torrentId, String link); Task UpdateStatus(Guid downloadId, DownloadStatus status); Task DeleteForTorrent(Guid torrentId); @@ -18,12 +19,10 @@ namespace RdtClient.Service.Services public class Downloads : IDownloads { private readonly IDownloadData _downloadData; - private readonly ISettings _settings; - public Downloads(IDownloadData downloadData, ISettings settings) + public Downloads(IDownloadData downloadData) { _downloadData = downloadData; - _settings = settings; } public async Task> Get() @@ -31,6 +30,11 @@ namespace RdtClient.Service.Services return await _downloadData.Get(); } + public async Task> GetForTorrent(Guid torrentId) + { + return await _downloadData.GetForTorrent(torrentId); + } + public async Task Add(Guid torrentId, String link) { return await _downloadData.Add(torrentId, link); diff --git a/server/RdtClient.Service/Services/QBittorrent.cs b/server/RdtClient.Service/Services/QBittorrent.cs index bf5b7fe..17ebae9 100644 --- a/server/RdtClient.Service/Services/QBittorrent.cs +++ b/server/RdtClient.Service/Services/QBittorrent.cs @@ -18,7 +18,7 @@ namespace RdtClient.Service.Services Task> TorrentInfo(); Task TorrentProperties(String hash); Task TorrentsDelete(String hash, Boolean deleteFiles); - Task TorrentsAdd(String url); + Task TorrentsAdd(String magnetLink, Boolean autoDownload, Boolean autoDelete); Task TorrentsSetCategory(String hash, String category); Task> TorrentsCategories(); } @@ -363,9 +363,9 @@ namespace RdtClient.Service.Services } } - public async Task TorrentsAdd(String url) + public async Task TorrentsAdd(String magnetLink, Boolean autoDownload, Boolean autoDelete) { - await _torrents.UploadMagnet(url); + await _torrents.UploadMagnet(magnetLink, autoDownload, autoDelete); } public async Task TorrentsSetCategory(String hash, String category) diff --git a/server/RdtClient.Service/Services/Scheduler.cs b/server/RdtClient.Service/Services/Scheduler.cs deleted file mode 100644 index 98e6767..0000000 --- a/server/RdtClient.Service/Services/Scheduler.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using Hangfire; -using RdtClient.Data.Enums; - -namespace RdtClient.Service.Services -{ - public interface IScheduler - { - void Start(); - Task Process(); - } - - public class Scheduler : IScheduler - { - private readonly IDownloads _downloads; - private readonly ISettings _settings; - private readonly ITorrents _torrents; - - public Scheduler(ITorrents torrents, IDownloads downloads, ISettings settings) - { - _torrents = torrents; - _downloads = downloads; - _settings = settings; - } - - public void Start() - { - RecurringJob.AddOrUpdate(() => Process(), "* * * * *"); - BackgroundJob.Enqueue(() => Process()); - } - - [DisableConcurrentExecution(5)] - public async Task Process() - { - await _torrents.Update(); - - var downloads = await _downloads.Get(); - - downloads = downloads.Where(m => m.Status != DownloadStatus.Finished) - .OrderByDescending(m => m.Status) - .ThenByDescending(m => m.Added) - .ToList(); - - var maxDownloads = await _settings.GetNumber("DownloadLimit"); - var destinationFolderPath = await _settings.GetString("DownloadFolder"); - - foreach (var download in downloads) - { - if (DownloadManager.ActiveDownloads.Count >= maxDownloads) - { - return; - } - - download.Torrent = null; - BackgroundJob.Enqueue(() => DownloadManager.Download(download, destinationFolderPath)); - - await Task.Delay(1000); - } - } - } -} \ No newline at end of file diff --git a/server/RdtClient.Service/Services/TaskRunner.cs b/server/RdtClient.Service/Services/TaskRunner.cs new file mode 100644 index 0000000..0ba95f0 --- /dev/null +++ b/server/RdtClient.Service/Services/TaskRunner.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using RdtClient.Data.Enums; + +namespace RdtClient.Service.Services +{ + public class TaskRunner : IHostedService, IDisposable + { + public static readonly ConcurrentDictionary ActiveDownloads = new ConcurrentDictionary(); + + private readonly ILogger _logger; + private readonly IServiceProvider _services; + + private Timer _timer; + + private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1); + + public TaskRunner(ILogger logger, IServiceProvider services) + { + _logger = logger; + _services = services; + } + + public Task StartAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("Timed Hosted Service running."); + + _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5)); + + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("Timed Hosted Service is stopping."); + + _timer?.Change(Timeout.Infinite, 0); + + return Task.CompletedTask; + } + + public void Dispose() + { + _timer?.Dispose(); + } + + private async void DoWork(Object state) + { + // Make sure only 1 process enters the lock + var obtainLock = await _semaphoreSlim.WaitAsync(100); + + if (!obtainLock) + { + return; + } + + try + { + using (var scope = _services.CreateScope()) + { + var downloads = scope.ServiceProvider.GetRequiredService(); + var settings = scope.ServiceProvider.GetRequiredService(); + var torrents = scope.ServiceProvider.GetRequiredService(); + + var rdKey = await settings.GetString("RealDebridApiKey"); + + if (String.IsNullOrWhiteSpace(rdKey)) + { + return; + } + + await ProcessAutoDownloads(downloads, settings, torrents); + await ProcessDownloads(downloads, settings, torrents); + await ProcessStatus(downloads, settings, torrents); + } + } + finally + { + _semaphoreSlim.Release(1); + } + } + + private async Task ProcessAutoDownloads(IDownloads downloads, ISettings settings, ITorrents torrents) + { + await torrents.Update(); + + var allTorrents = await torrents.Get(); + + allTorrents = allTorrents.Where(m => m.Status == TorrentStatus.WaitingForDownload && m.AutoDownload && m.Downloads.Count == 0) + .ToList(); + + foreach (var torrent in allTorrents) + { + await torrents.Download(torrent.TorrentId); + } + } + + private async Task ProcessDownloads(IDownloads downloads, ISettings settings, ITorrents torrents) + { + await torrents.Update(); + + var allDownloads = await downloads.Get(); + + allDownloads = allDownloads.Where(m => m.Status != DownloadStatus.Finished) + .OrderByDescending(m => m.Status) + .ThenByDescending(m => m.Added) + .ToList(); + + var maxDownloads = await settings.GetNumber("DownloadLimit"); + var destinationFolderPath = await settings.GetString("DownloadFolder"); + + foreach (var download in allDownloads) + { + if (ActiveDownloads.ContainsKey(download.DownloadId)) + { + continue; + } + + if (ActiveDownloads.Count >= maxDownloads) + { + return; + } + + // Prevent circular references + download.Torrent.Downloads = null; + + await Task.Factory.StartNew(async delegate + { + var downloadManager = new DownloadManager(); + + if (ActiveDownloads.TryAdd(download.DownloadId, downloadManager)) + { + downloadManager.Download = download; + await downloadManager.Start(destinationFolderPath); + + await torrents.UpdateStatus(download.TorrentId, TorrentStatus.Downloading); + } + }); + } + } + + private async Task ProcessStatus(IDownloads downloads, ISettings settings, ITorrents torrents) + { + foreach (var (downloadId, download) in ActiveDownloads) + { + if (download.NewStatus.HasValue) + { + download.Download.Status = download.NewStatus.Value; + download.NewStatus = null; + + await downloads.UpdateStatus(downloadId, download.Download.Status); + + if (download.Download.Status == DownloadStatus.Finished) + { + ActiveDownloads.TryRemove(downloadId, out _); + + // Check if all downloads are completed and update the torrent + var allDownloads = await downloads.GetForTorrent(download.Download.TorrentId); + + if (allDownloads.All(m => m.Status == DownloadStatus.Finished)) + { + await torrents.UpdateStatus(download.Download.TorrentId, TorrentStatus.Finished); + + if (download.Download.Torrent.AutoDelete) + { + await torrents.Delete(download.Download.TorrentId); + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/server/RdtClient.Service/Services/Torrents.cs b/server/RdtClient.Service/Services/Torrents.cs index 9f3e530..d68cef1 100644 --- a/server/RdtClient.Service/Services/Torrents.cs +++ b/server/RdtClient.Service/Services/Torrents.cs @@ -19,9 +19,10 @@ namespace RdtClient.Service.Services Task GetById(Guid id); Task GetByHash(String hash); Task> Update(); + Task UpdateStatus(Guid torrentId, TorrentStatus status); Task UpdateCategory(String hash, String category); - Task UploadMagnet(String magnetLink); - Task UploadFile(Byte[] bytes); + Task UploadMagnet(String magnetLink, Boolean autoDownload, Boolean autoDelete); + Task UploadFile(Byte[] bytes, Boolean autoDownload, Boolean autoDelete); Task Delete(Guid id); Task Download(Guid id); void Reset(); @@ -60,7 +61,7 @@ namespace RdtClient.Service.Services throw new Exception("RealDebrid API Key not set in the settings"); } - _rdtClient = new RdNetClient("X245A4XAIBGVM", null, null, null, null, apiKey); + _rdtClient = new RdNetClient("X245A4XAIBGVM", null, null, null, apiKey); } return _rdtClient; @@ -82,10 +83,11 @@ namespace RdtClient.Service.Services { foreach (var download in torrent.Downloads) { - if (DownloadManager.ActiveDownloads.TryGetValue(download.DownloadId, out var activeDownload)) + if (TaskRunner.ActiveDownloads.TryGetValue(download.DownloadId, out var activeDownload)) { download.Speed = activeDownload.Speed; - download.Progress = activeDownload.Progress; + download.BytesSize = activeDownload.BytesSize; + download.BytesDownloaded = activeDownload.BytesDownloaded; } } } @@ -99,7 +101,7 @@ namespace RdtClient.Service.Services if (torrent != null) { - var rdTorrent = await RdNetClient.TorrentInfoAsync(torrent.RdId); + var rdTorrent = await RdNetClient.GetTorrentInfoAsync(torrent.RdId); await Update(torrent, rdTorrent); } @@ -113,7 +115,7 @@ namespace RdtClient.Service.Services if (torrent != null) { - var rdTorrent = await RdNetClient.TorrentInfoAsync(torrent.RdId); + var rdTorrent = await RdNetClient.GetTorrentInfoAsync(torrent.RdId); await Update(torrent, rdTorrent); } @@ -133,7 +135,7 @@ namespace RdtClient.Service.Services try { - var rdTorrents = await RdNetClient.TorrentsAsync(0, 100); + var rdTorrents = await RdNetClient.GetTorrentsAsync(0, 100); foreach (var rdTorrent in rdTorrents) { @@ -169,6 +171,11 @@ namespace RdtClient.Service.Services } } + public async Task UpdateStatus(Guid torrentId, TorrentStatus status) + { + await _torrentData.UpdateStatus(torrentId, status); + } + public async Task UpdateCategory(String hash, String category) { var torrent = await _torrentData.GetByHash(hash); @@ -181,22 +188,22 @@ namespace RdtClient.Service.Services await _torrentData.UpdateCategory(torrent.TorrentId, category); } - public async Task UploadMagnet(String magnetLink) + public async Task UploadMagnet(String magnetLink, Boolean autoDownload, Boolean autoDelete) { var magnet = MagnetLink.Parse(magnetLink); - var rdTorrent = await RdNetClient.TorrentAddMagnet(magnetLink); + var rdTorrent = await RdNetClient.AddTorrentMagnetAsync(magnetLink); - await Add(rdTorrent.Id, magnet.InfoHash.ToHex()); + await Add(rdTorrent.Id, magnet.InfoHash.ToHex(), autoDownload, autoDelete); } - public async Task UploadFile(Byte[] bytes) + public async Task UploadFile(Byte[] bytes, Boolean autoDownload, Boolean autoDelete) { var torrent = MonoTorrent.Torrent.Load(bytes); - var rdTorrent = await RdNetClient.TorrentAddFile(bytes); + var rdTorrent = await RdNetClient.AddTorrentFileAsync(bytes); - await Add(rdTorrent.Id, torrent.InfoHash.ToHex()); + await Add(rdTorrent.Id, torrent.InfoHash.ToHex(), autoDownload, autoDelete); } public async Task Delete(Guid id) @@ -207,7 +214,7 @@ namespace RdtClient.Service.Services { await _downloads.DeleteForTorrent(torrent.TorrentId); await _torrentData.Delete(id); - await RdNetClient.TorrentDelete(torrent.RdId); + await RdNetClient.DeleteTorrentAsync(torrent.RdId); } } @@ -217,7 +224,9 @@ namespace RdtClient.Service.Services await _downloads.DeleteForTorrent(id); - var rdTorrent = await RdNetClient.TorrentInfoAsync(torrent.RdId); + await _torrentData.UpdateStatus(id, TorrentStatus.DownloadQueued); + + var rdTorrent = await RdNetClient.GetTorrentInfoAsync(torrent.RdId); foreach (var link in rdTorrent.Links) { @@ -235,7 +244,12 @@ namespace RdtClient.Service.Services public async Task GetProfile() { - var user = await _rdtClient.UserAsync(); + if (_rdtClient == null) + { + return new Profile(); + } + + var user = await _rdtClient.GetUserAsync(); var profile = new Profile { @@ -246,11 +260,11 @@ namespace RdtClient.Service.Services return profile; } - private async Task Add(String rdTorrentId, String infoHash) + private async Task Add(String rdTorrentId, String infoHash, Boolean autoDownload, Boolean autoDelete) { var newTorrent = await _torrentData.Add(rdTorrentId, infoHash); - var rdTorrent = await RdNetClient.TorrentInfoAsync(rdTorrentId); + var rdTorrent = await RdNetClient.GetTorrentInfoAsync(rdTorrentId); if (rdTorrent.Files != null && rdTorrent.Files.Count > 0) { @@ -259,14 +273,14 @@ namespace RdtClient.Service.Services var fileIds = rdTorrent.Files.Select(m => m.Id.ToString()) .ToArray(); - await RdNetClient.TorrentSelectFiles(rdTorrentId, fileIds); + await RdNetClient.SelectTorrentFilesAsync(rdTorrentId, fileIds); } } await Update(newTorrent, rdTorrent); } - private async Task Update(Torrent torrent, RDNET.Models.Torrent rdTorrent) + private async Task Update(Torrent torrent, RDNET.Torrent rdTorrent) { if (!String.IsNullOrWhiteSpace(rdTorrent.Filename)) { @@ -300,11 +314,13 @@ namespace RdtClient.Service.Services torrent.RdSpeed = rdTorrent.Speed; torrent.RdSeeders = rdTorrent.Seeders; + await _torrentData.UpdateRdData(torrent); + if (torrent.Status == TorrentStatus.RealDebrid) { if (torrent.Status == TorrentStatus.RealDebrid && torrent.RdProgress == 100) { - torrent.Status = TorrentStatus.WaitingForDownload; + await _torrentData.UpdateStatus(torrent.TorrentId, TorrentStatus.WaitingForDownload); } else { @@ -317,10 +333,10 @@ namespace RdtClient.Service.Services "dead" => TorrentStatus.Error, _ => TorrentStatus.RealDebrid }; + + await _torrentData.UpdateStatus(torrent.TorrentId, torrent.Status); } } - - await _torrentData.UpdateRdData(torrent); } } } \ No newline at end of file diff --git a/server/RdtClient.Web/Controllers/QBittorrentController.cs b/server/RdtClient.Web/Controllers/QBittorrentController.cs index 0a0f854..de47954 100644 --- a/server/RdtClient.Web/Controllers/QBittorrentController.cs +++ b/server/RdtClient.Web/Controllers/QBittorrentController.cs @@ -272,7 +272,7 @@ namespace RdtClient.Web.Controllers foreach (var url in urls) { - await _qBittorrent.TorrentsAdd(url.Trim()); + await _qBittorrent.TorrentsAdd(url.Trim(), true, true); } return Ok(); diff --git a/server/RdtClient.Web/Controllers/SettingsController.cs b/server/RdtClient.Web/Controllers/SettingsController.cs index 2f15ce9..f8b80e2 100644 --- a/server/RdtClient.Web/Controllers/SettingsController.cs +++ b/server/RdtClient.Web/Controllers/SettingsController.cs @@ -33,7 +33,7 @@ namespace RdtClient.Web.Controllers } catch (Exception ex) { - return BadRequest(ex); + return BadRequest(ex.Message); } } @@ -50,7 +50,7 @@ namespace RdtClient.Web.Controllers } catch (Exception ex) { - return BadRequest(ex); + return BadRequest(ex.Message); } } @@ -65,7 +65,7 @@ namespace RdtClient.Web.Controllers } catch (Exception ex) { - return BadRequest(ex); + return BadRequest(ex.Message); } } } diff --git a/server/RdtClient.Web/Controllers/TorrentsController.cs b/server/RdtClient.Web/Controllers/TorrentsController.cs index adf5a63..10ddc91 100644 --- a/server/RdtClient.Web/Controllers/TorrentsController.cs +++ b/server/RdtClient.Web/Controllers/TorrentsController.cs @@ -15,12 +15,10 @@ namespace RdtClient.Web.Controllers public class TorrentsController : Controller { private readonly ITorrents _torrents; - private readonly IScheduler _scheduler; - public TorrentsController(ITorrents torrents, IScheduler scheduler) + public TorrentsController(ITorrents torrents) { _torrents = torrents; - _scheduler = scheduler; } [HttpGet] @@ -34,7 +32,7 @@ namespace RdtClient.Web.Controllers } catch (Exception ex) { - return BadRequest(ex); + return BadRequest(ex.Message); } } @@ -55,7 +53,7 @@ namespace RdtClient.Web.Controllers } catch (Exception ex) { - return BadRequest(ex); + return BadRequest(ex.Message); } } @@ -78,7 +76,7 @@ namespace RdtClient.Web.Controllers var bytes = memoryStream.ToArray(); - await _torrents.UploadFile(bytes); + await _torrents.UploadFile(bytes, false, false); return Ok(); } @@ -94,7 +92,7 @@ namespace RdtClient.Web.Controllers { try { - await _torrents.UploadMagnet(request.MagnetLink); + await _torrents.UploadMagnet(request.MagnetLink, false, false); return Ok(); } @@ -127,7 +125,6 @@ namespace RdtClient.Web.Controllers try { await _torrents.Download(id); - await _scheduler.Process(); return Ok(); } diff --git a/server/RdtClient.Web/Program.cs b/server/RdtClient.Web/Program.cs index 0b39dc9..ca6aa2a 100644 --- a/server/RdtClient.Web/Program.cs +++ b/server/RdtClient.Web/Program.cs @@ -4,7 +4,6 @@ using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -using RdtClient.Data.Models.Internal; namespace RdtClient.Web { diff --git a/server/RdtClient.Web/RdtClient.Web.csproj b/server/RdtClient.Web/RdtClient.Web.csproj index 33a6dd0..6a6dba0 100644 --- a/server/RdtClient.Web/RdtClient.Web.csproj +++ b/server/RdtClient.Web/RdtClient.Web.csproj @@ -5,9 +5,6 @@ - - - @@ -17,7 +14,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/server/RdtClient.Web/Startup.cs b/server/RdtClient.Web/Startup.cs index 14dd689..c75094e 100644 --- a/server/RdtClient.Web/Startup.cs +++ b/server/RdtClient.Web/Startup.cs @@ -1,6 +1,4 @@ using System.Threading.Tasks; -using Hangfire; -using Hangfire.MemoryStorage; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -14,7 +12,6 @@ using Microsoft.Extensions.Logging; using RdtClient.Data; using RdtClient.Data.Data; using RdtClient.Data.Models.Internal; -using RdtClient.Service.Services; namespace RdtClient.Web { @@ -83,19 +80,11 @@ namespace RdtClient.Web options.Cookie.Name = "SID"; }); - services.AddHangfire(configuration => configuration - .SetDataCompatibilityLevel(CompatibilityLevel.Version_170) - .UseSimpleAssemblyNameTypeSerializer() - .UseRecommendedSerializerSettings() - .UseMemoryStorage()); - - services.AddHangfireServer(); - DiConfig.Config(services); Service.DiConfig.Config(services); } - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger logger, DataContext dataContext, IScheduler scheduler) + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger logger, DataContext dataContext) { if (env.IsDevelopment()) { @@ -107,9 +96,9 @@ namespace RdtClient.Web { await next.Invoke(); - if (context.Response.StatusCode >= 404) + if (context.Response.StatusCode != 200) { - logger.LogWarning($"404: {context.Request.Path.Value}"); + logger.LogWarning($"{context.Response.StatusCode}: {context.Request.Path.Value}"); } }); @@ -118,9 +107,7 @@ namespace RdtClient.Web app.UseAuthentication(); app.UseAuthorization(); - - app.UseHangfireServer(); - + app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); app.MapWhen(x => !x.Request.Path.Value.StartsWith("/api"), builder => @@ -134,8 +121,6 @@ namespace RdtClient.Web }); dataContext.Migrate(); - - scheduler.Start(); } } } \ No newline at end of file diff --git a/server/RdtClient.Web/wwwroot/index.html b/server/RdtClient.Web/wwwroot/index.html index 5e162dd..fc5ca18 100644 --- a/server/RdtClient.Web/wwwroot/index.html +++ b/server/RdtClient.Web/wwwroot/index.html @@ -9,5 +9,5 @@ - + diff --git a/server/libs/RDNET.deps.json b/server/libs/RDNET.deps.json deleted file mode 100644 index cae48d8..0000000 --- a/server/libs/RDNET.deps.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "runtimeTarget": { - "name": ".NETStandard,Version=v2.0/", - "signature": "" - }, - "compilationOptions": {}, - "targets": { - ".NETStandard,Version=v2.0": {}, - ".NETStandard,Version=v2.0/": { - "RDNET/1.0.0": { - "dependencies": { - "NETStandard.Library": "2.0.3", - "Newtonsoft.Json": "12.0.3" - }, - "runtime": { - "RDNET.dll": {} - } - }, - "Microsoft.NETCore.Platforms/1.1.0": {}, - "NETStandard.Library/2.0.3": { - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0" - } - }, - "Newtonsoft.Json/12.0.3": { - "runtime": { - "lib/netstandard2.0/Newtonsoft.Json.dll": { - "assemblyVersion": "12.0.0.0", - "fileVersion": "12.0.3.23909" - } - } - } - } - }, - "libraries": { - "RDNET/1.0.0": { - "type": "project", - "serviceable": false, - "sha512": "" - }, - "Microsoft.NETCore.Platforms/1.1.0": { - "type": "package", - "serviceable": true, - "sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==", - "path": "microsoft.netcore.platforms/1.1.0", - "hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512" - }, - "NETStandard.Library/2.0.3": { - "type": "package", - "serviceable": true, - "sha512": "sha512-st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", - "path": "netstandard.library/2.0.3", - "hashPath": "netstandard.library.2.0.3.nupkg.sha512" - }, - "Newtonsoft.Json/12.0.3": { - "type": "package", - "serviceable": true, - "sha512": "sha512-6mgjfnRB4jKMlzHSl+VD+oUc1IebOZabkbyWj2RiTgWwYPPuaK1H97G1sHqGwPlS5npiF5Q0OrxN1wni2n5QWg==", - "path": "newtonsoft.json/12.0.3", - "hashPath": "newtonsoft.json.12.0.3.nupkg.sha512" - } - } -} \ No newline at end of file diff --git a/server/libs/RDNET.dll b/server/libs/RDNET.dll deleted file mode 100644 index 9fb3f783262227af399b1e100e25b4963c3586bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66560 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 Z372*bxjFgtz?_mf3+`UOybHaL`F|?}coYBt