From 7f1a85d430009b2ece94708aded741b27f735381 Mon Sep 17 00:00:00 2001 From: kunkliricsi Date: Sat, 7 Nov 2020 14:19:29 +0100 Subject: [PATCH] Added Device services for back and frontend --- Birdmap.API/ClientApp/package-lock.json | 18 + Birdmap.API/ClientApp/package.json | 2 + .../src/components/devices/DeviceService.js | 601 ++++++++++++ .../components/devices/DeviceService.js.map | 1 + .../src/components/devices/DeviceService.ts | 599 ++++++++++++ .../src/components/heatmap/heatmap.js | 555 +++++++++++ .../src/components/heatmap/heatmap.js.map | 1 + .../src/components/heatmap/heatmap.ts | 561 +++++++++++ .../src/components/heatmap/heatmap.tsx | 21 + Birdmap.API/Controllers/AuthController.cs | 6 +- Birdmap.API/Controllers/DevicesController.cs | 144 +++ Birdmap.API/Controllers/ServicesController.cs | 12 +- Birdmap.API/appsettings.json | 3 +- Birdmap.BLL/Interfaces/IDeviceService.cs | 279 ++++++ Birdmap.BLL/Services/DeviceServiceBase.cs | 39 + Birdmap.BLL/Services/DummyDeviceService.cs | 139 +++ Birdmap.BLL/Services/LiveDeviceService.cs | 902 ++++++++++++++++++ Birdmap.BLL/Startup.cs | 5 + c-n-c-nswag.nswag | 221 +++++ c-n-c.yml | 272 ++++++ docs/Dashboard.jpg | Bin 0 -> 50055 bytes docs/Login.jpg | Bin 0 -> 55485 bytes 22 files changed, 4368 insertions(+), 13 deletions(-) create mode 100644 Birdmap.API/ClientApp/src/components/devices/DeviceService.js create mode 100644 Birdmap.API/ClientApp/src/components/devices/DeviceService.js.map create mode 100644 Birdmap.API/ClientApp/src/components/devices/DeviceService.ts create mode 100644 Birdmap.API/ClientApp/src/components/heatmap/heatmap.js create mode 100644 Birdmap.API/ClientApp/src/components/heatmap/heatmap.js.map create mode 100644 Birdmap.API/ClientApp/src/components/heatmap/heatmap.ts create mode 100644 Birdmap.API/ClientApp/src/components/heatmap/heatmap.tsx create mode 100644 Birdmap.API/Controllers/DevicesController.cs create mode 100644 Birdmap.BLL/Interfaces/IDeviceService.cs create mode 100644 Birdmap.BLL/Services/DeviceServiceBase.cs create mode 100644 Birdmap.BLL/Services/DummyDeviceService.cs create mode 100644 Birdmap.BLL/Services/LiveDeviceService.cs create mode 100644 c-n-c-nswag.nswag create mode 100644 c-n-c.yml create mode 100644 docs/Dashboard.jpg create mode 100644 docs/Login.jpg diff --git a/Birdmap.API/ClientApp/package-lock.json b/Birdmap.API/ClientApp/package-lock.json index 506d86f..cf85909 100644 --- a/Birdmap.API/ClientApp/package-lock.json +++ b/Birdmap.API/ClientApp/package-lock.json @@ -1733,6 +1733,11 @@ "@types/node": "*" } }, + "@types/googlemaps": { + "version": "3.40.3", + "resolved": "https://registry.npmjs.org/@types/googlemaps/-/googlemaps-3.40.3.tgz", + "integrity": "sha512-ivlG5S0LlnQgpgPnQCUNAs7kjBtO367ZwDmuK+ggsQfW+w4N0RyWbxWZ6vPwegDe50Du3Xbb5+QVwJuB/U1XpA==" + }, "@types/history": { "version": "4.7.3", "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.3.tgz", @@ -6321,6 +6326,19 @@ } } }, + "google-maps": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/google-maps/-/google-maps-4.3.3.tgz", + "integrity": "sha512-MQbEgBNQbGyV7mfS2tlFgW4EoGKLia24BvAl4a+kgsYWt4283kyPpaay/yKIsScQLr7nSUONaLNfOdMsCuJDEw==", + "requires": { + "@types/googlemaps": "^3.39.1" + } + }, + "google-maps-react": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/google-maps-react/-/google-maps-react-2.0.6.tgz", + "integrity": "sha512-M8Eo9WndfQEfxcmm6yRq03qdJgw1x6rQmJ9DN+a+xPQ3K7yNDGkVDbinrf4/8vcox7nELbeopbm4bpefKewWfQ==" + }, "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", diff --git a/Birdmap.API/ClientApp/package.json b/Birdmap.API/ClientApp/package.json index e5fe9fd..462cb73 100644 --- a/Birdmap.API/ClientApp/package.json +++ b/Birdmap.API/ClientApp/package.json @@ -8,6 +8,8 @@ "@material-ui/lab": "^4.0.0-alpha.56", "bootstrap": "^4.3.1", "connected-react-router": "6.5.2", + "google-maps": "^4.3.3", + "google-maps-react": "^2.0.6", "history": "4.10.1", "jquery": "^3.5.1", "merge": "1.2.1", diff --git a/Birdmap.API/ClientApp/src/components/devices/DeviceService.js b/Birdmap.API/ClientApp/src/components/devices/DeviceService.js new file mode 100644 index 0000000..25fda0c --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/devices/DeviceService.js @@ -0,0 +1,601 @@ +"use strict"; +/* tslint:disable */ +/* eslint-disable */ +//---------------------- +// +// Generated using the NSwag toolchain v13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0)) (http://NSwag.org) +// +//---------------------- +// ReSharper disable InconsistentNaming +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ApiException = exports.SensorStatus = exports.Coordinates = exports.DeviceStatus = exports.Sensor = exports.Device = exports.DeviceService = void 0; +var DeviceService = /** @class */ (function () { + function DeviceService(baseUrl, http) { + this.jsonParseReviver = undefined; + this.http = http ? http : window; + this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "api/devices"; + } + /** + * Get all device info + * @return Array of devices + */ + DeviceService.prototype.getall = function () { + var _this = this; + var url_ = this.baseUrl; + var options_ = { + method: "GET", + headers: { + "Accept": "application/json" + } + }; + return this.http.fetch(url_, options_).then(function (_response) { + return _this.processGetall(_response); + }); + }; + DeviceService.prototype.processGetall = function (response) { + var _this = this; + var status = response.status; + var _headers = {}; + if (response.headers && response.headers.forEach) { + response.headers.forEach(function (v, k) { return _headers[k] = v; }); + } + ; + if (status === 200) { + return response.text().then(function (_responseText) { + var result200 = null; + var resultData200 = _responseText === "" ? null : JSON.parse(_responseText, _this.jsonParseReviver); + if (Array.isArray(resultData200)) { + result200 = []; + for (var _i = 0, resultData200_1 = resultData200; _i < resultData200_1.length; _i++) { + var item = resultData200_1[_i]; + result200.push(Device.fromJS(item)); + } + } + return result200; + }); + } + else if (status === 404) { + return response.text().then(function (_responseText) { + return throwException("No device found", status, _responseText, _headers); + }); + } + else if (status !== 200 && status !== 204) { + return response.text().then(function (_responseText) { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + }; + /** + * Shut down all devices + * @return Message sent + */ + DeviceService.prototype.offlineall = function () { + var _this = this; + var url_ = this.baseUrl + "/offline"; + url_ = url_.replace(/[?&]$/, ""); + var options_ = { + method: "POST", + headers: {} + }; + return this.http.fetch(url_, options_).then(function (_response) { + return _this.processOfflineall(_response); + }); + }; + DeviceService.prototype.processOfflineall = function (response) { + var status = response.status; + var _headers = {}; + if (response.headers && response.headers.forEach) { + response.headers.forEach(function (v, k) { return _headers[k] = v; }); + } + ; + if (status === 200) { + return response.text().then(function (_responseText) { + return; + }); + } + else if (status === 500) { + return response.text().then(function (_responseText) { + return throwException("Message sending unsuccessful", status, _responseText, _headers); + }); + } + else if (status !== 200 && status !== 204) { + return response.text().then(function (_responseText) { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + }; + /** + * Bring all devices online + * @return Message sent + */ + DeviceService.prototype.onlineall = function () { + var _this = this; + var url_ = this.baseUrl + "/online"; + url_ = url_.replace(/[?&]$/, ""); + var options_ = { + method: "POST", + headers: {} + }; + return this.http.fetch(url_, options_).then(function (_response) { + return _this.processOnlineall(_response); + }); + }; + DeviceService.prototype.processOnlineall = function (response) { + var status = response.status; + var _headers = {}; + if (response.headers && response.headers.forEach) { + response.headers.forEach(function (v, k) { return _headers[k] = v; }); + } + ; + if (status === 200) { + return response.text().then(function (_responseText) { + return; + }); + } + else if (status === 500) { + return response.text().then(function (_responseText) { + return throwException("Message sending unsuccessful", status, _responseText, _headers); + }); + } + else if (status !== 200 && status !== 204) { + return response.text().then(function (_responseText) { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + }; + /** + * Get all device info + * @param deviceID ID of device to query + * @return Information about a particular device + */ + DeviceService.prototype.getdevice = function (deviceID) { + var _this = this; + var url_ = this.baseUrl + "/{deviceID}"; + if (deviceID === undefined || deviceID === null) + throw new Error("The parameter 'deviceID' must be defined."); + url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID)); + url_ = url_.replace(/[?&]$/, ""); + var options_ = { + method: "GET", + headers: { + "Accept": "application/json" + } + }; + return this.http.fetch(url_, options_).then(function (_response) { + return _this.processGetdevice(_response); + }); + }; + DeviceService.prototype.processGetdevice = function (response) { + var _this = this; + var status = response.status; + var _headers = {}; + if (response.headers && response.headers.forEach) { + response.headers.forEach(function (v, k) { return _headers[k] = v; }); + } + ; + if (status === 200) { + return response.text().then(function (_responseText) { + var result200 = null; + var resultData200 = _responseText === "" ? null : JSON.parse(_responseText, _this.jsonParseReviver); + result200 = Device.fromJS(resultData200); + return result200; + }); + } + else if (status === 404) { + return response.text().then(function (_responseText) { + return throwException("Device not found", status, _responseText, _headers); + }); + } + else if (status !== 200 && status !== 204) { + return response.text().then(function (_responseText) { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + }; + /** + * Shut down device + * @param deviceID ID of device to shut down + * @return Message sent + */ + DeviceService.prototype.offlinedevice = function (deviceID) { + var _this = this; + var url_ = this.baseUrl + "/{deviceID}/offline"; + if (deviceID === undefined || deviceID === null) + throw new Error("The parameter 'deviceID' must be defined."); + url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID)); + url_ = url_.replace(/[?&]$/, ""); + var options_ = { + method: "POST", + headers: {} + }; + return this.http.fetch(url_, options_).then(function (_response) { + return _this.processOfflinedevice(_response); + }); + }; + DeviceService.prototype.processOfflinedevice = function (response) { + var status = response.status; + var _headers = {}; + if (response.headers && response.headers.forEach) { + response.headers.forEach(function (v, k) { return _headers[k] = v; }); + } + ; + if (status === 200) { + return response.text().then(function (_responseText) { + return; + }); + } + else if (status === 500) { + return response.text().then(function (_responseText) { + return throwException("Message sending unsuccessful", status, _responseText, _headers); + }); + } + else if (status !== 200 && status !== 204) { + return response.text().then(function (_responseText) { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + }; + /** + * Bring device online + * @param deviceID ID of device to bring online + * @return Message sent + */ + DeviceService.prototype.onlinedevice = function (deviceID) { + var _this = this; + var url_ = this.baseUrl + "/{deviceID}/online"; + if (deviceID === undefined || deviceID === null) + throw new Error("The parameter 'deviceID' must be defined."); + url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID)); + url_ = url_.replace(/[?&]$/, ""); + var options_ = { + method: "POST", + headers: {} + }; + return this.http.fetch(url_, options_).then(function (_response) { + return _this.processOnlinedevice(_response); + }); + }; + DeviceService.prototype.processOnlinedevice = function (response) { + var status = response.status; + var _headers = {}; + if (response.headers && response.headers.forEach) { + response.headers.forEach(function (v, k) { return _headers[k] = v; }); + } + ; + if (status === 200) { + return response.text().then(function (_responseText) { + return; + }); + } + else if (status === 500) { + return response.text().then(function (_responseText) { + return throwException("Message sending unsuccessful", status, _responseText, _headers); + }); + } + else if (status !== 200 && status !== 204) { + return response.text().then(function (_responseText) { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + }; + /** + * Get info about a particular device's sensor + * @param deviceID ID of device to query + * @param sensorID ID of sensor to query + * @return Information about a sensor + */ + DeviceService.prototype.getsensor = function (deviceID, sensorID) { + var _this = this; + var url_ = this.baseUrl + "/{deviceID}/{sensorID}"; + if (deviceID === undefined || deviceID === null) + throw new Error("The parameter 'deviceID' must be defined."); + url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID)); + if (sensorID === undefined || sensorID === null) + throw new Error("The parameter 'sensorID' must be defined."); + url_ = url_.replace("{sensorID}", encodeURIComponent("" + sensorID)); + url_ = url_.replace(/[?&]$/, ""); + var options_ = { + method: "GET", + headers: { + "Accept": "application/json" + } + }; + return this.http.fetch(url_, options_).then(function (_response) { + return _this.processGetsensor(_response); + }); + }; + DeviceService.prototype.processGetsensor = function (response) { + var _this = this; + var status = response.status; + var _headers = {}; + if (response.headers && response.headers.forEach) { + response.headers.forEach(function (v, k) { return _headers[k] = v; }); + } + ; + if (status === 200) { + return response.text().then(function (_responseText) { + var result200 = null; + var resultData200 = _responseText === "" ? null : JSON.parse(_responseText, _this.jsonParseReviver); + result200 = Sensor.fromJS(resultData200); + return result200; + }); + } + else if (status === 404) { + return response.text().then(function (_responseText) { + return throwException("Device or sensor not found", status, _responseText, _headers); + }); + } + else if (status !== 200 && status !== 204) { + return response.text().then(function (_responseText) { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + }; + /** + * Shut down sensor + * @param deviceID ID of device to query + * @param sensorID ID of sensor to query + * @return Message sent + */ + DeviceService.prototype.offlinesensor = function (deviceID, sensorID) { + var _this = this; + var url_ = this.baseUrl + "/{deviceID}/{sensorID}/offline"; + if (deviceID === undefined || deviceID === null) + throw new Error("The parameter 'deviceID' must be defined."); + url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID)); + if (sensorID === undefined || sensorID === null) + throw new Error("The parameter 'sensorID' must be defined."); + url_ = url_.replace("{sensorID}", encodeURIComponent("" + sensorID)); + url_ = url_.replace(/[?&]$/, ""); + var options_ = { + method: "POST", + headers: {} + }; + return this.http.fetch(url_, options_).then(function (_response) { + return _this.processOfflinesensor(_response); + }); + }; + DeviceService.prototype.processOfflinesensor = function (response) { + var status = response.status; + var _headers = {}; + if (response.headers && response.headers.forEach) { + response.headers.forEach(function (v, k) { return _headers[k] = v; }); + } + ; + if (status === 200) { + return response.text().then(function (_responseText) { + return; + }); + } + else if (status === 500) { + return response.text().then(function (_responseText) { + return throwException("Message sending unsuccessful", status, _responseText, _headers); + }); + } + else if (status !== 200 && status !== 204) { + return response.text().then(function (_responseText) { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + }; + /** + * Bring sensor online + * @param deviceID ID of device to query + * @param sensorID ID of sensor to query + * @return Message sent + */ + DeviceService.prototype.onlinesensor = function (deviceID, sensorID) { + var _this = this; + var url_ = this.baseUrl + "/{deviceID}/{sensorID}/online"; + if (deviceID === undefined || deviceID === null) + throw new Error("The parameter 'deviceID' must be defined."); + url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID)); + if (sensorID === undefined || sensorID === null) + throw new Error("The parameter 'sensorID' must be defined."); + url_ = url_.replace("{sensorID}", encodeURIComponent("" + sensorID)); + url_ = url_.replace(/[?&]$/, ""); + var options_ = { + method: "POST", + headers: {} + }; + return this.http.fetch(url_, options_).then(function (_response) { + return _this.processOnlinesensor(_response); + }); + }; + DeviceService.prototype.processOnlinesensor = function (response) { + var status = response.status; + var _headers = {}; + if (response.headers && response.headers.forEach) { + response.headers.forEach(function (v, k) { return _headers[k] = v; }); + } + ; + if (status === 200) { + return response.text().then(function (_responseText) { + return; + }); + } + else if (status === 500) { + return response.text().then(function (_responseText) { + return throwException("Message sending unsuccessful", status, _responseText, _headers); + }); + } + else if (status !== 200 && status !== 204) { + return response.text().then(function (_responseText) { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + }; + return DeviceService; +}()); +exports.DeviceService = DeviceService; +var Device = /** @class */ (function () { + function Device(data) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + this[property] = data[property]; + } + } + if (!data) { + this.coordinates = new Coordinates(); + this.sensors = []; + } + } + Device.prototype.init = function (_data) { + if (_data) { + this.id = _data["id"]; + this.status = _data["status"]; + this.url = _data["url"]; + this.coordinates = _data["coordinates"] ? Coordinates.fromJS(_data["coordinates"]) : new Coordinates(); + if (Array.isArray(_data["sensors"])) { + this.sensors = []; + for (var _i = 0, _a = _data["sensors"]; _i < _a.length; _i++) { + var item = _a[_i]; + this.sensors.push(Sensor.fromJS(item)); + } + } + } + }; + Device.fromJS = function (data) { + data = typeof data === 'object' ? data : {}; + var result = new Device(); + result.init(data); + return result; + }; + Device.prototype.toJSON = function (data) { + data = typeof data === 'object' ? data : {}; + data["id"] = this.id; + data["status"] = this.status; + data["url"] = this.url; + data["coordinates"] = this.coordinates ? this.coordinates.toJSON() : undefined; + if (Array.isArray(this.sensors)) { + data["sensors"] = []; + for (var _i = 0, _a = this.sensors; _i < _a.length; _i++) { + var item = _a[_i]; + data["sensors"].push(item.toJSON()); + } + } + return data; + }; + return Device; +}()); +exports.Device = Device; +var Sensor = /** @class */ (function () { + function Sensor(data) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + this[property] = data[property]; + } + } + } + Sensor.prototype.init = function (_data) { + if (_data) { + this.id = _data["id"]; + this.status = _data["status"]; + } + }; + Sensor.fromJS = function (data) { + data = typeof data === 'object' ? data : {}; + var result = new Sensor(); + result.init(data); + return result; + }; + Sensor.prototype.toJSON = function (data) { + data = typeof data === 'object' ? data : {}; + data["id"] = this.id; + data["status"] = this.status; + return data; + }; + return Sensor; +}()); +exports.Sensor = Sensor; +var DeviceStatus; +(function (DeviceStatus) { + DeviceStatus["Online"] = "online"; + DeviceStatus["Error"] = "error"; + DeviceStatus["Offline"] = "offline"; +})(DeviceStatus = exports.DeviceStatus || (exports.DeviceStatus = {})); +var Coordinates = /** @class */ (function () { + function Coordinates(data) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + this[property] = data[property]; + } + } + } + Coordinates.prototype.init = function (_data) { + if (_data) { + this.latitude = _data["latitude"]; + this.longitude = _data["longitude"]; + } + }; + Coordinates.fromJS = function (data) { + data = typeof data === 'object' ? data : {}; + var result = new Coordinates(); + result.init(data); + return result; + }; + Coordinates.prototype.toJSON = function (data) { + data = typeof data === 'object' ? data : {}; + data["latitude"] = this.latitude; + data["longitude"] = this.longitude; + return data; + }; + return Coordinates; +}()); +exports.Coordinates = Coordinates; +var SensorStatus; +(function (SensorStatus) { + SensorStatus["Online"] = "online"; + SensorStatus["Unknown"] = "unknown"; + SensorStatus["Offline"] = "offline"; +})(SensorStatus = exports.SensorStatus || (exports.SensorStatus = {})); +var ApiException = /** @class */ (function (_super) { + __extends(ApiException, _super); + function ApiException(message, status, response, headers, result) { + var _this = _super.call(this) || this; + _this.isApiException = true; + _this.message = message; + _this.status = status; + _this.response = response; + _this.headers = headers; + _this.result = result; + return _this; + } + ApiException.isApiException = function (obj) { + return obj.isApiException === true; + }; + return ApiException; +}(Error)); +exports.ApiException = ApiException; +function throwException(message, status, response, headers, result) { + if (result !== null && result !== undefined) + throw result; + else + throw new ApiException(message, status, response, headers, null); +} +//# sourceMappingURL=DeviceService.js.map \ No newline at end of file diff --git a/Birdmap.API/ClientApp/src/components/devices/DeviceService.js.map b/Birdmap.API/ClientApp/src/components/devices/DeviceService.js.map new file mode 100644 index 0000000..e562720 --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/devices/DeviceService.js.map @@ -0,0 +1 @@ +{"version":3,"file":"DeviceService.js","sourceRoot":"","sources":["DeviceService.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/Birdmap.API/ClientApp/src/components/devices/DeviceService.ts b/Birdmap.API/ClientApp/src/components/devices/DeviceService.ts new file mode 100644 index 0000000..5230923 --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/devices/DeviceService.ts @@ -0,0 +1,599 @@ +/* tslint:disable */ +/* eslint-disable */ +//---------------------- +// +// Generated using the NSwag toolchain v13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0)) (http://NSwag.org) +// +//---------------------- +// ReSharper disable InconsistentNaming + +export class DeviceService { + private http: { fetch(url: RequestInfo, init?: RequestInit): Promise }; + private baseUrl: string; + protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined; + + constructor(baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise }) { + this.http = http ? http : window; + this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : "api/devices"; + } + + /** + * Get all device info + * @return Array of devices + */ + getall(): Promise { + let url_ = this.baseUrl; + + let options_ = { + method: "GET", + headers: { + "Accept": "application/json" + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processGetall(_response); + }); + } + + protected processGetall(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + if (Array.isArray(resultData200)) { + result200 = [] as any; + for (let item of resultData200) + result200!.push(Device.fromJS(item)); + } + return result200; + }); + } else if (status === 404) { + return response.text().then((_responseText) => { + return throwException("No device found", status, _responseText, _headers); + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + } + + /** + * Shut down all devices + * @return Message sent + */ + offlineall(): Promise { + let url_ = this.baseUrl + "/offline"; + url_ = url_.replace(/[?&]$/, ""); + + let options_ = { + method: "POST", + headers: { + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processOfflineall(_response); + }); + } + + protected processOfflineall(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + return; + }); + } else if (status === 500) { + return response.text().then((_responseText) => { + return throwException("Message sending unsuccessful", status, _responseText, _headers); + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + } + + /** + * Bring all devices online + * @return Message sent + */ + onlineall(): Promise { + let url_ = this.baseUrl + "/online"; + url_ = url_.replace(/[?&]$/, ""); + + let options_ = { + method: "POST", + headers: { + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processOnlineall(_response); + }); + } + + protected processOnlineall(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + return; + }); + } else if (status === 500) { + return response.text().then((_responseText) => { + return throwException("Message sending unsuccessful", status, _responseText, _headers); + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + } + + /** + * Get all device info + * @param deviceID ID of device to query + * @return Information about a particular device + */ + getdevice(deviceID: string): Promise { + let url_ = this.baseUrl + "/{deviceID}"; + if (deviceID === undefined || deviceID === null) + throw new Error("The parameter 'deviceID' must be defined."); + url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID)); + url_ = url_.replace(/[?&]$/, ""); + + let options_ = { + method: "GET", + headers: { + "Accept": "application/json" + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processGetdevice(_response); + }); + } + + protected processGetdevice(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + result200 = Device.fromJS(resultData200); + return result200; + }); + } else if (status === 404) { + return response.text().then((_responseText) => { + return throwException("Device not found", status, _responseText, _headers); + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + } + + /** + * Shut down device + * @param deviceID ID of device to shut down + * @return Message sent + */ + offlinedevice(deviceID: string): Promise { + let url_ = this.baseUrl + "/{deviceID}/offline"; + if (deviceID === undefined || deviceID === null) + throw new Error("The parameter 'deviceID' must be defined."); + url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID)); + url_ = url_.replace(/[?&]$/, ""); + + let options_ = { + method: "POST", + headers: { + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processOfflinedevice(_response); + }); + } + + protected processOfflinedevice(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + return; + }); + } else if (status === 500) { + return response.text().then((_responseText) => { + return throwException("Message sending unsuccessful", status, _responseText, _headers); + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + } + + /** + * Bring device online + * @param deviceID ID of device to bring online + * @return Message sent + */ + onlinedevice(deviceID: string): Promise { + let url_ = this.baseUrl + "/{deviceID}/online"; + if (deviceID === undefined || deviceID === null) + throw new Error("The parameter 'deviceID' must be defined."); + url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID)); + url_ = url_.replace(/[?&]$/, ""); + + let options_ = { + method: "POST", + headers: { + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processOnlinedevice(_response); + }); + } + + protected processOnlinedevice(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + return; + }); + } else if (status === 500) { + return response.text().then((_responseText) => { + return throwException("Message sending unsuccessful", status, _responseText, _headers); + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + } + + /** + * Get info about a particular device's sensor + * @param deviceID ID of device to query + * @param sensorID ID of sensor to query + * @return Information about a sensor + */ + getsensor(deviceID: string, sensorID: string): Promise { + let url_ = this.baseUrl + "/{deviceID}/{sensorID}"; + if (deviceID === undefined || deviceID === null) + throw new Error("The parameter 'deviceID' must be defined."); + url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID)); + if (sensorID === undefined || sensorID === null) + throw new Error("The parameter 'sensorID' must be defined."); + url_ = url_.replace("{sensorID}", encodeURIComponent("" + sensorID)); + url_ = url_.replace(/[?&]$/, ""); + + let options_ = { + method: "GET", + headers: { + "Accept": "application/json" + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processGetsensor(_response); + }); + } + + protected processGetsensor(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + result200 = Sensor.fromJS(resultData200); + return result200; + }); + } else if (status === 404) { + return response.text().then((_responseText) => { + return throwException("Device or sensor not found", status, _responseText, _headers); + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + } + + /** + * Shut down sensor + * @param deviceID ID of device to query + * @param sensorID ID of sensor to query + * @return Message sent + */ + offlinesensor(deviceID: string, sensorID: string): Promise { + let url_ = this.baseUrl + "/{deviceID}/{sensorID}/offline"; + if (deviceID === undefined || deviceID === null) + throw new Error("The parameter 'deviceID' must be defined."); + url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID)); + if (sensorID === undefined || sensorID === null) + throw new Error("The parameter 'sensorID' must be defined."); + url_ = url_.replace("{sensorID}", encodeURIComponent("" + sensorID)); + url_ = url_.replace(/[?&]$/, ""); + + let options_ = { + method: "POST", + headers: { + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processOfflinesensor(_response); + }); + } + + protected processOfflinesensor(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + return; + }); + } else if (status === 500) { + return response.text().then((_responseText) => { + return throwException("Message sending unsuccessful", status, _responseText, _headers); + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + } + + /** + * Bring sensor online + * @param deviceID ID of device to query + * @param sensorID ID of sensor to query + * @return Message sent + */ + onlinesensor(deviceID: string, sensorID: string): Promise { + let url_ = this.baseUrl + "/{deviceID}/{sensorID}/online"; + if (deviceID === undefined || deviceID === null) + throw new Error("The parameter 'deviceID' must be defined."); + url_ = url_.replace("{deviceID}", encodeURIComponent("" + deviceID)); + if (sensorID === undefined || sensorID === null) + throw new Error("The parameter 'sensorID' must be defined."); + url_ = url_.replace("{sensorID}", encodeURIComponent("" + sensorID)); + url_ = url_.replace(/[?&]$/, ""); + + let options_ = { + method: "POST", + headers: { + } + }; + + return this.http.fetch(url_, options_).then((_response: Response) => { + return this.processOnlinesensor(_response); + }); + } + + protected processOnlinesensor(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + return; + }); + } else if (status === 500) { + return response.text().then((_responseText) => { + return throwException("Message sending unsuccessful", status, _responseText, _headers); + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null); + } +} + +export class Device implements IDevice { + id!: string; + status!: DeviceStatus; + url!: string; + coordinates!: Coordinates; + sensors!: Sensor[]; + + constructor(data?: IDevice) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + if (!data) { + this.coordinates = new Coordinates(); + this.sensors = []; + } + } + + init(_data?: any) { + if (_data) { + this.id = _data["id"]; + this.status = _data["status"]; + this.url = _data["url"]; + this.coordinates = _data["coordinates"] ? Coordinates.fromJS(_data["coordinates"]) : new Coordinates(); + if (Array.isArray(_data["sensors"])) { + this.sensors = [] as any; + for (let item of _data["sensors"]) + this.sensors!.push(Sensor.fromJS(item)); + } + } + } + + static fromJS(data: any): Device { + data = typeof data === 'object' ? data : {}; + let result = new Device(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["id"] = this.id; + data["status"] = this.status; + data["url"] = this.url; + data["coordinates"] = this.coordinates ? this.coordinates.toJSON() : undefined; + if (Array.isArray(this.sensors)) { + data["sensors"] = []; + for (let item of this.sensors) + data["sensors"].push(item.toJSON()); + } + return data; + } +} + +export interface IDevice { + id: string; + status: DeviceStatus; + url: string; + coordinates: Coordinates; + sensors: Sensor[]; +} + +export class Sensor implements ISensor { + id!: string; + status!: SensorStatus; + + constructor(data?: ISensor) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.id = _data["id"]; + this.status = _data["status"]; + } + } + + static fromJS(data: any): Sensor { + data = typeof data === 'object' ? data : {}; + let result = new Sensor(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["id"] = this.id; + data["status"] = this.status; + return data; + } +} + +export interface ISensor { + id: string; + status: SensorStatus; +} + +export enum DeviceStatus { + Online = "online", + Error = "error", + Offline = "offline", +} + +export class Coordinates implements ICoordinates { + latitude!: number; + longitude!: number; + + constructor(data?: ICoordinates) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.latitude = _data["latitude"]; + this.longitude = _data["longitude"]; + } + } + + static fromJS(data: any): Coordinates { + data = typeof data === 'object' ? data : {}; + let result = new Coordinates(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["latitude"] = this.latitude; + data["longitude"] = this.longitude; + return data; + } +} + +export interface ICoordinates { + latitude: number; + longitude: number; +} + +export enum SensorStatus { + Online = "online", + Unknown = "unknown", + Offline = "offline", +} + +export class ApiException extends Error { + message: string; + status: number; + response: string; + headers: { [key: string]: any; }; + result: any; + + constructor(message: string, status: number, response: string, headers: { [key: string]: any; }, result: any) { + super(); + + this.message = message; + this.status = status; + this.response = response; + this.headers = headers; + this.result = result; + } + + protected isApiException = true; + + static isApiException(obj: any): obj is ApiException { + return obj.isApiException === true; + } +} + +function throwException(message: string, status: number, response: string, headers: { [key: string]: any; }, result?: any): any { + if (result !== null && result !== undefined) + throw result; + else + throw new ApiException(message, status, response, headers, null); +} \ No newline at end of file diff --git a/Birdmap.API/ClientApp/src/components/heatmap/heatmap.js b/Birdmap.API/ClientApp/src/components/heatmap/heatmap.js new file mode 100644 index 0000000..0e3bc3e --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/heatmap/heatmap.js @@ -0,0 +1,555 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.initMap = void 0; +var google_maps_1 = require("google-maps"); +var map, heatmap; +function initMap() { + var options = { /* todo */}; + var loader = new google_maps_1.Loader('AIzaSyCZ51VFfxqZ2GkCmVrcNZdUKsM0fuBQUCY', options); + loader.load().then(function (google) { + map = new google.maps.Map(document.getElementById("map"), { + zoom: 13, + center: { lat: 37.775, lng: -122.434 }, + mapTypeId: "satellite", + }); + heatmap = new google.maps.visualization.HeatmapLayer({ + data: getPoints(), + map: map, + }); + }); +} +exports.initMap = initMap; +function toggleHeatmap() { + heatmap.setMap(heatmap.getMap() ? null : map); +} +function changeGradient() { + var gradient = [ + "rgba(0, 255, 255, 0)", + "rgba(0, 255, 255, 1)", + "rgba(0, 191, 255, 1)", + "rgba(0, 127, 255, 1)", + "rgba(0, 63, 255, 1)", + "rgba(0, 0, 255, 1)", + "rgba(0, 0, 223, 1)", + "rgba(0, 0, 191, 1)", + "rgba(0, 0, 159, 1)", + "rgba(0, 0, 127, 1)", + "rgba(63, 0, 91, 1)", + "rgba(127, 0, 63, 1)", + "rgba(191, 0, 31, 1)", + "rgba(255, 0, 0, 1)", + ]; + heatmap.set("gradient", heatmap.get("gradient") ? null : gradient); +} +function changeRadius() { + heatmap.set("radius", heatmap.get("radius") ? null : 20); +} +function changeOpacity() { + heatmap.set("opacity", heatmap.get("opacity") ? null : 0.2); +} +// Heatmap data: 500 Points +function getPoints() { + return [ + new google.maps.LatLng(37.782551, -122.445368), + new google.maps.LatLng(37.782745, -122.444586), + new google.maps.LatLng(37.782842, -122.443688), + new google.maps.LatLng(37.782919, -122.442815), + new google.maps.LatLng(37.782992, -122.442112), + new google.maps.LatLng(37.7831, -122.441461), + new google.maps.LatLng(37.783206, -122.440829), + new google.maps.LatLng(37.783273, -122.440324), + new google.maps.LatLng(37.783316, -122.440023), + new google.maps.LatLng(37.783357, -122.439794), + new google.maps.LatLng(37.783371, -122.439687), + new google.maps.LatLng(37.783368, -122.439666), + new google.maps.LatLng(37.783383, -122.439594), + new google.maps.LatLng(37.783508, -122.439525), + new google.maps.LatLng(37.783842, -122.439591), + new google.maps.LatLng(37.784147, -122.439668), + new google.maps.LatLng(37.784206, -122.439686), + new google.maps.LatLng(37.784386, -122.43979), + new google.maps.LatLng(37.784701, -122.439902), + new google.maps.LatLng(37.784965, -122.439938), + new google.maps.LatLng(37.78501, -122.439947), + new google.maps.LatLng(37.78536, -122.439952), + new google.maps.LatLng(37.785715, -122.44003), + new google.maps.LatLng(37.786117, -122.440119), + new google.maps.LatLng(37.786564, -122.440209), + new google.maps.LatLng(37.786905, -122.44027), + new google.maps.LatLng(37.786956, -122.440279), + new google.maps.LatLng(37.800224, -122.43352), + new google.maps.LatLng(37.800155, -122.434101), + new google.maps.LatLng(37.80016, -122.43443), + new google.maps.LatLng(37.800378, -122.434527), + new google.maps.LatLng(37.800738, -122.434598), + new google.maps.LatLng(37.800938, -122.43465), + new google.maps.LatLng(37.801024, -122.434889), + new google.maps.LatLng(37.800955, -122.435392), + new google.maps.LatLng(37.800886, -122.435959), + new google.maps.LatLng(37.800811, -122.436275), + new google.maps.LatLng(37.800788, -122.436299), + new google.maps.LatLng(37.800719, -122.436302), + new google.maps.LatLng(37.800702, -122.436298), + new google.maps.LatLng(37.800661, -122.436273), + new google.maps.LatLng(37.800395, -122.436172), + new google.maps.LatLng(37.800228, -122.436116), + new google.maps.LatLng(37.800169, -122.43613), + new google.maps.LatLng(37.800066, -122.436167), + new google.maps.LatLng(37.784345, -122.422922), + new google.maps.LatLng(37.784389, -122.422926), + new google.maps.LatLng(37.784437, -122.422924), + new google.maps.LatLng(37.784746, -122.422818), + new google.maps.LatLng(37.785436, -122.422959), + new google.maps.LatLng(37.78612, -122.423112), + new google.maps.LatLng(37.786433, -122.423029), + new google.maps.LatLng(37.786631, -122.421213), + new google.maps.LatLng(37.78666, -122.421033), + new google.maps.LatLng(37.786801, -122.420141), + new google.maps.LatLng(37.786823, -122.420034), + new google.maps.LatLng(37.786831, -122.419916), + new google.maps.LatLng(37.787034, -122.418208), + new google.maps.LatLng(37.787056, -122.418034), + new google.maps.LatLng(37.787169, -122.417145), + new google.maps.LatLng(37.787217, -122.416715), + new google.maps.LatLng(37.786144, -122.416403), + new google.maps.LatLng(37.785292, -122.416257), + new google.maps.LatLng(37.780666, -122.390374), + new google.maps.LatLng(37.780501, -122.391281), + new google.maps.LatLng(37.780148, -122.392052), + new google.maps.LatLng(37.780173, -122.391148), + new google.maps.LatLng(37.780693, -122.390592), + new google.maps.LatLng(37.781261, -122.391142), + new google.maps.LatLng(37.781808, -122.39173), + new google.maps.LatLng(37.78234, -122.392341), + new google.maps.LatLng(37.782812, -122.393022), + new google.maps.LatLng(37.7833, -122.393672), + new google.maps.LatLng(37.783809, -122.394275), + new google.maps.LatLng(37.784246, -122.394979), + new google.maps.LatLng(37.784791, -122.395958), + new google.maps.LatLng(37.785675, -122.396746), + new google.maps.LatLng(37.786262, -122.39578), + new google.maps.LatLng(37.786776, -122.395093), + new google.maps.LatLng(37.787282, -122.394426), + new google.maps.LatLng(37.787783, -122.393767), + new google.maps.LatLng(37.788343, -122.393184), + new google.maps.LatLng(37.788895, -122.392506), + new google.maps.LatLng(37.789371, -122.391701), + new google.maps.LatLng(37.789722, -122.390952), + new google.maps.LatLng(37.790315, -122.390305), + new google.maps.LatLng(37.790738, -122.389616), + new google.maps.LatLng(37.779448, -122.438702), + new google.maps.LatLng(37.779023, -122.438585), + new google.maps.LatLng(37.778542, -122.438492), + new google.maps.LatLng(37.7781, -122.438411), + new google.maps.LatLng(37.777986, -122.438376), + new google.maps.LatLng(37.77768, -122.438313), + new google.maps.LatLng(37.777316, -122.438273), + new google.maps.LatLng(37.777135, -122.438254), + new google.maps.LatLng(37.776987, -122.438303), + new google.maps.LatLng(37.776946, -122.438404), + new google.maps.LatLng(37.776944, -122.438467), + new google.maps.LatLng(37.776892, -122.438459), + new google.maps.LatLng(37.776842, -122.438442), + new google.maps.LatLng(37.776822, -122.438391), + new google.maps.LatLng(37.776814, -122.438412), + new google.maps.LatLng(37.776787, -122.438628), + new google.maps.LatLng(37.776729, -122.43865), + new google.maps.LatLng(37.776759, -122.438677), + new google.maps.LatLng(37.776772, -122.438498), + new google.maps.LatLng(37.776787, -122.438389), + new google.maps.LatLng(37.776848, -122.438283), + new google.maps.LatLng(37.77687, -122.438239), + new google.maps.LatLng(37.777015, -122.438198), + new google.maps.LatLng(37.777333, -122.438256), + new google.maps.LatLng(37.777595, -122.438308), + new google.maps.LatLng(37.777797, -122.438344), + new google.maps.LatLng(37.77816, -122.438442), + new google.maps.LatLng(37.778414, -122.438508), + new google.maps.LatLng(37.778445, -122.438516), + new google.maps.LatLng(37.778503, -122.438529), + new google.maps.LatLng(37.778607, -122.438549), + new google.maps.LatLng(37.77867, -122.438644), + new google.maps.LatLng(37.778847, -122.438706), + new google.maps.LatLng(37.77924, -122.438744), + new google.maps.LatLng(37.779738, -122.438822), + new google.maps.LatLng(37.780201, -122.438882), + new google.maps.LatLng(37.7804, -122.438905), + new google.maps.LatLng(37.780501, -122.438921), + new google.maps.LatLng(37.780892, -122.438986), + new google.maps.LatLng(37.781446, -122.439087), + new google.maps.LatLng(37.781985, -122.439199), + new google.maps.LatLng(37.782239, -122.439249), + new google.maps.LatLng(37.782286, -122.439266), + new google.maps.LatLng(37.797847, -122.429388), + new google.maps.LatLng(37.797874, -122.42918), + new google.maps.LatLng(37.797885, -122.429069), + new google.maps.LatLng(37.797887, -122.42905), + new google.maps.LatLng(37.797933, -122.428954), + new google.maps.LatLng(37.798242, -122.42899), + new google.maps.LatLng(37.798617, -122.429075), + new google.maps.LatLng(37.798719, -122.429092), + new google.maps.LatLng(37.798944, -122.429145), + new google.maps.LatLng(37.79932, -122.429251), + new google.maps.LatLng(37.79959, -122.429309), + new google.maps.LatLng(37.799677, -122.429324), + new google.maps.LatLng(37.799966, -122.42936), + new google.maps.LatLng(37.800288, -122.42943), + new google.maps.LatLng(37.800443, -122.429461), + new google.maps.LatLng(37.800465, -122.429474), + new google.maps.LatLng(37.800644, -122.42954), + new google.maps.LatLng(37.800948, -122.42962), + new google.maps.LatLng(37.801242, -122.429685), + new google.maps.LatLng(37.801375, -122.429702), + new google.maps.LatLng(37.8014, -122.429703), + new google.maps.LatLng(37.801453, -122.429707), + new google.maps.LatLng(37.801473, -122.429709), + new google.maps.LatLng(37.801532, -122.429707), + new google.maps.LatLng(37.801852, -122.429729), + new google.maps.LatLng(37.802173, -122.429789), + new google.maps.LatLng(37.802459, -122.429847), + new google.maps.LatLng(37.802554, -122.429825), + new google.maps.LatLng(37.802647, -122.429549), + new google.maps.LatLng(37.802693, -122.429179), + new google.maps.LatLng(37.802729, -122.428751), + new google.maps.LatLng(37.766104, -122.409291), + new google.maps.LatLng(37.766103, -122.409268), + new google.maps.LatLng(37.766138, -122.409229), + new google.maps.LatLng(37.766183, -122.409231), + new google.maps.LatLng(37.766153, -122.409276), + new google.maps.LatLng(37.766005, -122.409365), + new google.maps.LatLng(37.765897, -122.40957), + new google.maps.LatLng(37.765767, -122.409739), + new google.maps.LatLng(37.765693, -122.410389), + new google.maps.LatLng(37.765615, -122.411201), + new google.maps.LatLng(37.765533, -122.412121), + new google.maps.LatLng(37.765467, -122.412939), + new google.maps.LatLng(37.765444, -122.414821), + new google.maps.LatLng(37.765444, -122.414964), + new google.maps.LatLng(37.765318, -122.415424), + new google.maps.LatLng(37.763961, -122.415296), + new google.maps.LatLng(37.763115, -122.415196), + new google.maps.LatLng(37.762967, -122.415183), + new google.maps.LatLng(37.762278, -122.415127), + new google.maps.LatLng(37.761675, -122.415055), + new google.maps.LatLng(37.760932, -122.414988), + new google.maps.LatLng(37.759337, -122.414862), + new google.maps.LatLng(37.773187, -122.421922), + new google.maps.LatLng(37.773043, -122.422118), + new google.maps.LatLng(37.773007, -122.422165), + new google.maps.LatLng(37.772979, -122.422219), + new google.maps.LatLng(37.772865, -122.422394), + new google.maps.LatLng(37.772779, -122.422503), + new google.maps.LatLng(37.772676, -122.422701), + new google.maps.LatLng(37.772606, -122.422806), + new google.maps.LatLng(37.772566, -122.42284), + new google.maps.LatLng(37.772508, -122.422852), + new google.maps.LatLng(37.772387, -122.423011), + new google.maps.LatLng(37.772099, -122.423328), + new google.maps.LatLng(37.771704, -122.423783), + new google.maps.LatLng(37.771481, -122.424081), + new google.maps.LatLng(37.7714, -122.424179), + new google.maps.LatLng(37.771352, -122.42422), + new google.maps.LatLng(37.771248, -122.424327), + new google.maps.LatLng(37.770904, -122.424781), + new google.maps.LatLng(37.77052, -122.425283), + new google.maps.LatLng(37.770337, -122.425553), + new google.maps.LatLng(37.770128, -122.425832), + new google.maps.LatLng(37.769756, -122.426331), + new google.maps.LatLng(37.7693, -122.426902), + new google.maps.LatLng(37.769132, -122.427065), + new google.maps.LatLng(37.769092, -122.427103), + new google.maps.LatLng(37.768979, -122.427172), + new google.maps.LatLng(37.768595, -122.427634), + new google.maps.LatLng(37.768372, -122.427913), + new google.maps.LatLng(37.768337, -122.427961), + new google.maps.LatLng(37.768244, -122.428138), + new google.maps.LatLng(37.767942, -122.428581), + new google.maps.LatLng(37.767482, -122.429094), + new google.maps.LatLng(37.767031, -122.429606), + new google.maps.LatLng(37.766732, -122.429986), + new google.maps.LatLng(37.76668, -122.430058), + new google.maps.LatLng(37.766633, -122.430109), + new google.maps.LatLng(37.76658, -122.430211), + new google.maps.LatLng(37.766367, -122.430594), + new google.maps.LatLng(37.76591, -122.431137), + new google.maps.LatLng(37.765353, -122.431806), + new google.maps.LatLng(37.764962, -122.432298), + new google.maps.LatLng(37.764868, -122.432486), + new google.maps.LatLng(37.764518, -122.432913), + new google.maps.LatLng(37.763435, -122.434173), + new google.maps.LatLng(37.762847, -122.434953), + new google.maps.LatLng(37.762291, -122.435935), + new google.maps.LatLng(37.762224, -122.436074), + new google.maps.LatLng(37.761957, -122.436892), + new google.maps.LatLng(37.761652, -122.438886), + new google.maps.LatLng(37.761284, -122.439955), + new google.maps.LatLng(37.76121, -122.440068), + new google.maps.LatLng(37.761064, -122.44072), + new google.maps.LatLng(37.76104, -122.441411), + new google.maps.LatLng(37.761048, -122.442324), + new google.maps.LatLng(37.760851, -122.443118), + new google.maps.LatLng(37.759977, -122.444591), + new google.maps.LatLng(37.759913, -122.444698), + new google.maps.LatLng(37.759623, -122.445065), + new google.maps.LatLng(37.758902, -122.445158), + new google.maps.LatLng(37.758428, -122.44457), + new google.maps.LatLng(37.757687, -122.44334), + new google.maps.LatLng(37.757583, -122.44324), + new google.maps.LatLng(37.757019, -122.442787), + new google.maps.LatLng(37.756603, -122.442322), + new google.maps.LatLng(37.75638, -122.441602), + new google.maps.LatLng(37.75579, -122.441382), + new google.maps.LatLng(37.754493, -122.442133), + new google.maps.LatLng(37.754361, -122.442206), + new google.maps.LatLng(37.753719, -122.44265), + new google.maps.LatLng(37.753096, -122.442915), + new google.maps.LatLng(37.751617, -122.443211), + new google.maps.LatLng(37.751496, -122.443246), + new google.maps.LatLng(37.750733, -122.443428), + new google.maps.LatLng(37.750126, -122.443536), + new google.maps.LatLng(37.750103, -122.443784), + new google.maps.LatLng(37.75039, -122.44401), + new google.maps.LatLng(37.750448, -122.444013), + new google.maps.LatLng(37.750536, -122.44404), + new google.maps.LatLng(37.750493, -122.444141), + new google.maps.LatLng(37.790859, -122.402808), + new google.maps.LatLng(37.790864, -122.402768), + new google.maps.LatLng(37.790995, -122.402539), + new google.maps.LatLng(37.791148, -122.402172), + new google.maps.LatLng(37.791385, -122.401312), + new google.maps.LatLng(37.791405, -122.400776), + new google.maps.LatLng(37.791288, -122.400528), + new google.maps.LatLng(37.791113, -122.400441), + new google.maps.LatLng(37.791027, -122.400395), + new google.maps.LatLng(37.791094, -122.400311), + new google.maps.LatLng(37.791211, -122.400183), + new google.maps.LatLng(37.79106, -122.399334), + new google.maps.LatLng(37.790538, -122.398718), + new google.maps.LatLng(37.790095, -122.398086), + new google.maps.LatLng(37.789644, -122.39736), + new google.maps.LatLng(37.789254, -122.396844), + new google.maps.LatLng(37.788855, -122.396397), + new google.maps.LatLng(37.788483, -122.395963), + new google.maps.LatLng(37.788015, -122.395365), + new google.maps.LatLng(37.787558, -122.394735), + new google.maps.LatLng(37.787472, -122.394323), + new google.maps.LatLng(37.78763, -122.394025), + new google.maps.LatLng(37.787767, -122.393987), + new google.maps.LatLng(37.787486, -122.394452), + new google.maps.LatLng(37.786977, -122.395043), + new google.maps.LatLng(37.786583, -122.395552), + new google.maps.LatLng(37.78654, -122.39561), + new google.maps.LatLng(37.786516, -122.395659), + new google.maps.LatLng(37.786378, -122.395707), + new google.maps.LatLng(37.786044, -122.395362), + new google.maps.LatLng(37.785598, -122.394715), + new google.maps.LatLng(37.785321, -122.394361), + new google.maps.LatLng(37.785207, -122.394236), + new google.maps.LatLng(37.785751, -122.394062), + new google.maps.LatLng(37.785996, -122.393881), + new google.maps.LatLng(37.786092, -122.39383), + new google.maps.LatLng(37.785998, -122.393899), + new google.maps.LatLng(37.785114, -122.394365), + new google.maps.LatLng(37.785022, -122.394441), + new google.maps.LatLng(37.784823, -122.394635), + new google.maps.LatLng(37.784719, -122.394629), + new google.maps.LatLng(37.785069, -122.394176), + new google.maps.LatLng(37.7855, -122.39365), + new google.maps.LatLng(37.78577, -122.393291), + new google.maps.LatLng(37.785839, -122.393159), + new google.maps.LatLng(37.782651, -122.400628), + new google.maps.LatLng(37.782616, -122.400599), + new google.maps.LatLng(37.782702, -122.40047), + new google.maps.LatLng(37.782915, -122.400192), + new google.maps.LatLng(37.783137, -122.399887), + new google.maps.LatLng(37.783414, -122.399519), + new google.maps.LatLng(37.783629, -122.399237), + new google.maps.LatLng(37.783688, -122.399157), + new google.maps.LatLng(37.783716, -122.399106), + new google.maps.LatLng(37.783798, -122.399072), + new google.maps.LatLng(37.783997, -122.399186), + new google.maps.LatLng(37.784271, -122.399538), + new google.maps.LatLng(37.784577, -122.399948), + new google.maps.LatLng(37.784828, -122.40026), + new google.maps.LatLng(37.784999, -122.400477), + new google.maps.LatLng(37.785113, -122.400651), + new google.maps.LatLng(37.785155, -122.400703), + new google.maps.LatLng(37.785192, -122.400749), + new google.maps.LatLng(37.785278, -122.400839), + new google.maps.LatLng(37.785387, -122.400857), + new google.maps.LatLng(37.785478, -122.40089), + new google.maps.LatLng(37.785526, -122.401022), + new google.maps.LatLng(37.785598, -122.401148), + new google.maps.LatLng(37.785631, -122.401202), + new google.maps.LatLng(37.78566, -122.401267), + new google.maps.LatLng(37.803986, -122.426035), + new google.maps.LatLng(37.804102, -122.425089), + new google.maps.LatLng(37.804211, -122.424156), + new google.maps.LatLng(37.803861, -122.423385), + new google.maps.LatLng(37.803151, -122.423214), + new google.maps.LatLng(37.802439, -122.423077), + new google.maps.LatLng(37.80174, -122.422905), + new google.maps.LatLng(37.801069, -122.422785), + new google.maps.LatLng(37.800345, -122.422649), + new google.maps.LatLng(37.799633, -122.422603), + new google.maps.LatLng(37.79975, -122.4217), + new google.maps.LatLng(37.799885, -122.420854), + new google.maps.LatLng(37.799209, -122.420607), + new google.maps.LatLng(37.795656, -122.400395), + new google.maps.LatLng(37.795203, -122.400304), + new google.maps.LatLng(37.778738, -122.415584), + new google.maps.LatLng(37.778812, -122.415189), + new google.maps.LatLng(37.778824, -122.415092), + new google.maps.LatLng(37.778833, -122.414932), + new google.maps.LatLng(37.778834, -122.414898), + new google.maps.LatLng(37.77874, -122.414757), + new google.maps.LatLng(37.778501, -122.414433), + new google.maps.LatLng(37.778182, -122.414026), + new google.maps.LatLng(37.777851, -122.413623), + new google.maps.LatLng(37.777486, -122.413166), + new google.maps.LatLng(37.777109, -122.412674), + new google.maps.LatLng(37.776743, -122.412186), + new google.maps.LatLng(37.77644, -122.4118), + new google.maps.LatLng(37.776295, -122.411614), + new google.maps.LatLng(37.776158, -122.41144), + new google.maps.LatLng(37.775806, -122.410997), + new google.maps.LatLng(37.775422, -122.410484), + new google.maps.LatLng(37.775126, -122.410087), + new google.maps.LatLng(37.775012, -122.409854), + new google.maps.LatLng(37.775164, -122.409573), + new google.maps.LatLng(37.775498, -122.40918), + new google.maps.LatLng(37.775868, -122.40873), + new google.maps.LatLng(37.776256, -122.40824), + new google.maps.LatLng(37.776519, -122.407928), + new google.maps.LatLng(37.776539, -122.407904), + new google.maps.LatLng(37.776595, -122.407854), + new google.maps.LatLng(37.776853, -122.407547), + new google.maps.LatLng(37.777234, -122.407087), + new google.maps.LatLng(37.777644, -122.406558), + new google.maps.LatLng(37.778066, -122.406017), + new google.maps.LatLng(37.778468, -122.405499), + new google.maps.LatLng(37.778866, -122.404995), + new google.maps.LatLng(37.779295, -122.404455), + new google.maps.LatLng(37.779695, -122.40395), + new google.maps.LatLng(37.779982, -122.403584), + new google.maps.LatLng(37.780295, -122.403223), + new google.maps.LatLng(37.780664, -122.402766), + new google.maps.LatLng(37.781043, -122.402288), + new google.maps.LatLng(37.781399, -122.401823), + new google.maps.LatLng(37.781727, -122.401407), + new google.maps.LatLng(37.781853, -122.401247), + new google.maps.LatLng(37.781894, -122.401195), + new google.maps.LatLng(37.782076, -122.400977), + new google.maps.LatLng(37.782338, -122.400603), + new google.maps.LatLng(37.782666, -122.400133), + new google.maps.LatLng(37.783048, -122.399634), + new google.maps.LatLng(37.78345, -122.399198), + new google.maps.LatLng(37.783791, -122.398998), + new google.maps.LatLng(37.784177, -122.398959), + new google.maps.LatLng(37.784388, -122.398971), + new google.maps.LatLng(37.784404, -122.399128), + new google.maps.LatLng(37.784586, -122.399524), + new google.maps.LatLng(37.784835, -122.399927), + new google.maps.LatLng(37.785116, -122.400307), + new google.maps.LatLng(37.785282, -122.400539), + new google.maps.LatLng(37.785346, -122.400692), + new google.maps.LatLng(37.765769, -122.407201), + new google.maps.LatLng(37.76579, -122.407414), + new google.maps.LatLng(37.765802, -122.407755), + new google.maps.LatLng(37.765791, -122.408219), + new google.maps.LatLng(37.765763, -122.408759), + new google.maps.LatLng(37.765726, -122.409348), + new google.maps.LatLng(37.765716, -122.409882), + new google.maps.LatLng(37.765708, -122.410202), + new google.maps.LatLng(37.765705, -122.410253), + new google.maps.LatLng(37.765707, -122.410369), + new google.maps.LatLng(37.765692, -122.41072), + new google.maps.LatLng(37.765699, -122.411215), + new google.maps.LatLng(37.765687, -122.411789), + new google.maps.LatLng(37.765666, -122.412373), + new google.maps.LatLng(37.765598, -122.412883), + new google.maps.LatLng(37.765543, -122.413039), + new google.maps.LatLng(37.765532, -122.413125), + new google.maps.LatLng(37.7655, -122.413553), + new google.maps.LatLng(37.765448, -122.414053), + new google.maps.LatLng(37.765388, -122.414645), + new google.maps.LatLng(37.765323, -122.41525), + new google.maps.LatLng(37.765303, -122.415847), + new google.maps.LatLng(37.765251, -122.416439), + new google.maps.LatLng(37.765204, -122.41702), + new google.maps.LatLng(37.765172, -122.417556), + new google.maps.LatLng(37.765164, -122.418075), + new google.maps.LatLng(37.765153, -122.418618), + new google.maps.LatLng(37.765136, -122.419112), + new google.maps.LatLng(37.765129, -122.419378), + new google.maps.LatLng(37.765119, -122.419481), + new google.maps.LatLng(37.7651, -122.419852), + new google.maps.LatLng(37.765083, -122.420349), + new google.maps.LatLng(37.765045, -122.42093), + new google.maps.LatLng(37.764992, -122.421481), + new google.maps.LatLng(37.76498, -122.421695), + new google.maps.LatLng(37.764993, -122.421843), + new google.maps.LatLng(37.764986, -122.422255), + new google.maps.LatLng(37.764975, -122.422823), + new google.maps.LatLng(37.764939, -122.423411), + new google.maps.LatLng(37.764902, -122.424014), + new google.maps.LatLng(37.764853, -122.424576), + new google.maps.LatLng(37.764826, -122.424922), + new google.maps.LatLng(37.764796, -122.425375), + new google.maps.LatLng(37.764782, -122.425869), + new google.maps.LatLng(37.764768, -122.426089), + new google.maps.LatLng(37.764766, -122.426117), + new google.maps.LatLng(37.764723, -122.426276), + new google.maps.LatLng(37.764681, -122.426649), + new google.maps.LatLng(37.782012, -122.4042), + new google.maps.LatLng(37.781574, -122.404911), + new google.maps.LatLng(37.781055, -122.405597), + new google.maps.LatLng(37.780479, -122.406341), + new google.maps.LatLng(37.779996, -122.406939), + new google.maps.LatLng(37.779459, -122.407613), + new google.maps.LatLng(37.778953, -122.408228), + new google.maps.LatLng(37.778409, -122.408839), + new google.maps.LatLng(37.777842, -122.409501), + new google.maps.LatLng(37.777334, -122.410181), + new google.maps.LatLng(37.776809, -122.410836), + new google.maps.LatLng(37.77624, -122.411514), + new google.maps.LatLng(37.775725, -122.412145), + new google.maps.LatLng(37.77519, -122.412805), + new google.maps.LatLng(37.774672, -122.413464), + new google.maps.LatLng(37.774084, -122.414186), + new google.maps.LatLng(37.773533, -122.413636), + new google.maps.LatLng(37.773021, -122.413009), + new google.maps.LatLng(37.772501, -122.412371), + new google.maps.LatLng(37.771964, -122.411681), + new google.maps.LatLng(37.771479, -122.411078), + new google.maps.LatLng(37.770992, -122.410477), + new google.maps.LatLng(37.770467, -122.409801), + new google.maps.LatLng(37.77009, -122.408904), + new google.maps.LatLng(37.769657, -122.408103), + new google.maps.LatLng(37.769132, -122.407276), + new google.maps.LatLng(37.768564, -122.406469), + new google.maps.LatLng(37.76798, -122.405745), + new google.maps.LatLng(37.76738, -122.405299), + new google.maps.LatLng(37.766604, -122.405297), + new google.maps.LatLng(37.765838, -122.4052), + new google.maps.LatLng(37.765139, -122.405139), + new google.maps.LatLng(37.764457, -122.405094), + new google.maps.LatLng(37.763716, -122.405142), + new google.maps.LatLng(37.762932, -122.405398), + new google.maps.LatLng(37.762126, -122.405813), + new google.maps.LatLng(37.761344, -122.406215), + new google.maps.LatLng(37.760556, -122.406495), + new google.maps.LatLng(37.759732, -122.406484), + new google.maps.LatLng(37.75891, -122.406228), + new google.maps.LatLng(37.758182, -122.405695), + new google.maps.LatLng(37.757676, -122.405118), + new google.maps.LatLng(37.757039, -122.404346), + new google.maps.LatLng(37.756335, -122.403719), + new google.maps.LatLng(37.755503, -122.403406), + new google.maps.LatLng(37.754665, -122.403242), + new google.maps.LatLng(37.753837, -122.403172), + new google.maps.LatLng(37.752986, -122.403112), + new google.maps.LatLng(37.751266, -122.403355), + ]; +} +//# sourceMappingURL=heatmap.js.map \ No newline at end of file diff --git a/Birdmap.API/ClientApp/src/components/heatmap/heatmap.js.map b/Birdmap.API/ClientApp/src/components/heatmap/heatmap.js.map new file mode 100644 index 0000000..6a72953 --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/heatmap/heatmap.js.map @@ -0,0 +1 @@ +{"version":3,"file":"heatmap.js","sourceRoot":"","sources":["heatmap.ts"],"names":[],"mappings":";;;AAAA,2CAAoD;AAEpD,IAAI,GAAoB,EAAE,OAA+C,CAAC;AAE1E,SAAS,OAAO;IACZ,IAAM,OAAO,GAAkB,EAAC,UAAU,CAAE,CAAC;IAC7C,IAAM,MAAM,GAAG,IAAI,oBAAM,CAAC,yCAAyC,EAAE,OAAO,CAAC,CAAC;IAE9E,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,UAAU,MAAM;QAC/B,GAAG,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAgB,EAAE;YACrE,IAAI,EAAE,EAAE;YACR,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE;YACtC,SAAS,EAAE,WAAW;SACzB,CAAC,CAAC;QAEH,OAAO,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC;YACjD,IAAI,EAAE,SAAS,EAAE;YACjB,GAAG,EAAE,GAAG;SACX,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC;AA4hBQ,0BAAO;AA1hBhB,SAAS,aAAa;IACpB,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,cAAc;IACrB,IAAM,QAAQ,GAAG;QACf,sBAAsB;QACtB,sBAAsB;QACtB,sBAAsB;QACtB,sBAAsB;QACtB,qBAAqB;QACrB,oBAAoB;QACpB,oBAAoB;QACpB,oBAAoB;QACpB,oBAAoB;QACpB,oBAAoB;QACpB,oBAAoB;QACpB,qBAAqB;QACrB,qBAAqB;QACrB,oBAAoB;KACrB,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,YAAY;IACnB,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,aAAa;IACpB,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC9D,CAAC;AAED,2BAA2B;AAC3B,SAAS,SAAS;IAChB,OAAO;QACL,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC;QAC5C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC;QAC5C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE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,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC;QAC5C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC;QAC5C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC;QAC5C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC;QAC5C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC;QAC5C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,SAAS,CAAC;QAC3C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC;QAC3C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC;QAC3C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,SAAS,CAAC;QAC7C,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,MAA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"} \ No newline at end of file diff --git a/Birdmap.API/ClientApp/src/components/heatmap/heatmap.ts b/Birdmap.API/ClientApp/src/components/heatmap/heatmap.ts new file mode 100644 index 0000000..183f6da --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/heatmap/heatmap.ts @@ -0,0 +1,561 @@ +import { Loader, LoaderOptions } from 'google-maps'; + +let map: google.maps.Map, heatmap: google.maps.visualization.HeatmapLayer; + +function initMap(): void { + const options: LoaderOptions = {/* todo */ }; + const loader = new Loader('AIzaSyCZ51VFfxqZ2GkCmVrcNZdUKsM0fuBQUCY', options); + + loader.load().then(function (google) { + map = new google.maps.Map(document.getElementById("map") as HTMLElement, { + zoom: 13, + center: { lat: 37.775, lng: -122.434 }, + mapTypeId: "satellite", + }); + + heatmap = new google.maps.visualization.HeatmapLayer({ + data: getPoints(), + map: map, + }); + }); +} + +function toggleHeatmap() { + heatmap.setMap(heatmap.getMap() ? null : map); +} + +function changeGradient() { + const gradient = [ + "rgba(0, 255, 255, 0)", + "rgba(0, 255, 255, 1)", + "rgba(0, 191, 255, 1)", + "rgba(0, 127, 255, 1)", + "rgba(0, 63, 255, 1)", + "rgba(0, 0, 255, 1)", + "rgba(0, 0, 223, 1)", + "rgba(0, 0, 191, 1)", + "rgba(0, 0, 159, 1)", + "rgba(0, 0, 127, 1)", + "rgba(63, 0, 91, 1)", + "rgba(127, 0, 63, 1)", + "rgba(191, 0, 31, 1)", + "rgba(255, 0, 0, 1)", + ]; + heatmap.set("gradient", heatmap.get("gradient") ? null : gradient); +} + +function changeRadius() { + heatmap.set("radius", heatmap.get("radius") ? null : 20); +} + +function changeOpacity() { + heatmap.set("opacity", heatmap.get("opacity") ? null : 0.2); +} + +// Heatmap data: 500 Points +function getPoints() { + return [ + new google.maps.LatLng(37.782551, -122.445368), + new google.maps.LatLng(37.782745, -122.444586), + new google.maps.LatLng(37.782842, -122.443688), + new google.maps.LatLng(37.782919, -122.442815), + new google.maps.LatLng(37.782992, -122.442112), + new google.maps.LatLng(37.7831, -122.441461), + new google.maps.LatLng(37.783206, -122.440829), + new google.maps.LatLng(37.783273, -122.440324), + new google.maps.LatLng(37.783316, -122.440023), + new google.maps.LatLng(37.783357, -122.439794), + new google.maps.LatLng(37.783371, -122.439687), + new google.maps.LatLng(37.783368, -122.439666), + new google.maps.LatLng(37.783383, -122.439594), + new google.maps.LatLng(37.783508, -122.439525), + new google.maps.LatLng(37.783842, -122.439591), + new google.maps.LatLng(37.784147, -122.439668), + new google.maps.LatLng(37.784206, -122.439686), + new google.maps.LatLng(37.784386, -122.43979), + new google.maps.LatLng(37.784701, -122.439902), + new google.maps.LatLng(37.784965, -122.439938), + new google.maps.LatLng(37.78501, -122.439947), + new google.maps.LatLng(37.78536, -122.439952), + new google.maps.LatLng(37.785715, -122.44003), + new google.maps.LatLng(37.786117, -122.440119), + new google.maps.LatLng(37.786564, -122.440209), + new google.maps.LatLng(37.786905, -122.44027), + new google.maps.LatLng(37.786956, -122.440279), + new google.maps.LatLng(37.800224, -122.43352), + new google.maps.LatLng(37.800155, -122.434101), + new google.maps.LatLng(37.80016, -122.43443), + new google.maps.LatLng(37.800378, -122.434527), + new google.maps.LatLng(37.800738, -122.434598), + new google.maps.LatLng(37.800938, -122.43465), + new google.maps.LatLng(37.801024, -122.434889), + new google.maps.LatLng(37.800955, -122.435392), + new google.maps.LatLng(37.800886, -122.435959), + new google.maps.LatLng(37.800811, -122.436275), + new google.maps.LatLng(37.800788, -122.436299), + new google.maps.LatLng(37.800719, -122.436302), + new google.maps.LatLng(37.800702, -122.436298), + new google.maps.LatLng(37.800661, -122.436273), + new google.maps.LatLng(37.800395, -122.436172), + new google.maps.LatLng(37.800228, -122.436116), + new google.maps.LatLng(37.800169, -122.43613), + new google.maps.LatLng(37.800066, -122.436167), + new google.maps.LatLng(37.784345, -122.422922), + new google.maps.LatLng(37.784389, -122.422926), + new google.maps.LatLng(37.784437, -122.422924), + new google.maps.LatLng(37.784746, -122.422818), + new google.maps.LatLng(37.785436, -122.422959), + new google.maps.LatLng(37.78612, -122.423112), + new google.maps.LatLng(37.786433, -122.423029), + new google.maps.LatLng(37.786631, -122.421213), + new google.maps.LatLng(37.78666, -122.421033), + new google.maps.LatLng(37.786801, -122.420141), + new google.maps.LatLng(37.786823, -122.420034), + new google.maps.LatLng(37.786831, -122.419916), + new google.maps.LatLng(37.787034, -122.418208), + new google.maps.LatLng(37.787056, -122.418034), + new google.maps.LatLng(37.787169, -122.417145), + new google.maps.LatLng(37.787217, -122.416715), + new google.maps.LatLng(37.786144, -122.416403), + new google.maps.LatLng(37.785292, -122.416257), + new google.maps.LatLng(37.780666, -122.390374), + new google.maps.LatLng(37.780501, -122.391281), + new google.maps.LatLng(37.780148, -122.392052), + new google.maps.LatLng(37.780173, -122.391148), + new google.maps.LatLng(37.780693, -122.390592), + new google.maps.LatLng(37.781261, -122.391142), + new google.maps.LatLng(37.781808, -122.39173), + new google.maps.LatLng(37.78234, -122.392341), + new google.maps.LatLng(37.782812, -122.393022), + new google.maps.LatLng(37.7833, -122.393672), + new google.maps.LatLng(37.783809, -122.394275), + new google.maps.LatLng(37.784246, -122.394979), + new google.maps.LatLng(37.784791, -122.395958), + new google.maps.LatLng(37.785675, -122.396746), + new google.maps.LatLng(37.786262, -122.39578), + new google.maps.LatLng(37.786776, -122.395093), + new google.maps.LatLng(37.787282, -122.394426), + new google.maps.LatLng(37.787783, -122.393767), + new google.maps.LatLng(37.788343, -122.393184), + new google.maps.LatLng(37.788895, -122.392506), + new google.maps.LatLng(37.789371, -122.391701), + new google.maps.LatLng(37.789722, -122.390952), + new google.maps.LatLng(37.790315, -122.390305), + new google.maps.LatLng(37.790738, -122.389616), + new google.maps.LatLng(37.779448, -122.438702), + new google.maps.LatLng(37.779023, -122.438585), + new google.maps.LatLng(37.778542, -122.438492), + new google.maps.LatLng(37.7781, -122.438411), + new google.maps.LatLng(37.777986, -122.438376), + new google.maps.LatLng(37.77768, -122.438313), + new google.maps.LatLng(37.777316, -122.438273), + new google.maps.LatLng(37.777135, -122.438254), + new google.maps.LatLng(37.776987, -122.438303), + new google.maps.LatLng(37.776946, -122.438404), + new google.maps.LatLng(37.776944, -122.438467), + new google.maps.LatLng(37.776892, -122.438459), + new google.maps.LatLng(37.776842, -122.438442), + new google.maps.LatLng(37.776822, -122.438391), + new google.maps.LatLng(37.776814, -122.438412), + new google.maps.LatLng(37.776787, -122.438628), + new google.maps.LatLng(37.776729, -122.43865), + new google.maps.LatLng(37.776759, -122.438677), + new google.maps.LatLng(37.776772, -122.438498), + new google.maps.LatLng(37.776787, -122.438389), + new google.maps.LatLng(37.776848, -122.438283), + new google.maps.LatLng(37.77687, -122.438239), + new google.maps.LatLng(37.777015, -122.438198), + new google.maps.LatLng(37.777333, -122.438256), + new google.maps.LatLng(37.777595, -122.438308), + new google.maps.LatLng(37.777797, -122.438344), + new google.maps.LatLng(37.77816, -122.438442), + new google.maps.LatLng(37.778414, -122.438508), + new google.maps.LatLng(37.778445, -122.438516), + new google.maps.LatLng(37.778503, -122.438529), + new google.maps.LatLng(37.778607, -122.438549), + new google.maps.LatLng(37.77867, -122.438644), + new google.maps.LatLng(37.778847, -122.438706), + new google.maps.LatLng(37.77924, -122.438744), + new google.maps.LatLng(37.779738, -122.438822), + new google.maps.LatLng(37.780201, -122.438882), + new google.maps.LatLng(37.7804, -122.438905), + new google.maps.LatLng(37.780501, -122.438921), + new google.maps.LatLng(37.780892, -122.438986), + new google.maps.LatLng(37.781446, -122.439087), + new google.maps.LatLng(37.781985, -122.439199), + new google.maps.LatLng(37.782239, -122.439249), + new google.maps.LatLng(37.782286, -122.439266), + new google.maps.LatLng(37.797847, -122.429388), + new google.maps.LatLng(37.797874, -122.42918), + new google.maps.LatLng(37.797885, -122.429069), + new google.maps.LatLng(37.797887, -122.42905), + new google.maps.LatLng(37.797933, -122.428954), + new google.maps.LatLng(37.798242, -122.42899), + new google.maps.LatLng(37.798617, -122.429075), + new google.maps.LatLng(37.798719, -122.429092), + new google.maps.LatLng(37.798944, -122.429145), + new google.maps.LatLng(37.79932, -122.429251), + new google.maps.LatLng(37.79959, -122.429309), + new google.maps.LatLng(37.799677, -122.429324), + new google.maps.LatLng(37.799966, -122.42936), + new google.maps.LatLng(37.800288, -122.42943), + new google.maps.LatLng(37.800443, -122.429461), + new google.maps.LatLng(37.800465, -122.429474), + new google.maps.LatLng(37.800644, -122.42954), + new google.maps.LatLng(37.800948, -122.42962), + new google.maps.LatLng(37.801242, -122.429685), + new google.maps.LatLng(37.801375, -122.429702), + new google.maps.LatLng(37.8014, -122.429703), + new google.maps.LatLng(37.801453, -122.429707), + new google.maps.LatLng(37.801473, -122.429709), + new google.maps.LatLng(37.801532, -122.429707), + new google.maps.LatLng(37.801852, -122.429729), + new google.maps.LatLng(37.802173, -122.429789), + new google.maps.LatLng(37.802459, -122.429847), + new google.maps.LatLng(37.802554, -122.429825), + new google.maps.LatLng(37.802647, -122.429549), + new google.maps.LatLng(37.802693, -122.429179), + new google.maps.LatLng(37.802729, -122.428751), + new google.maps.LatLng(37.766104, -122.409291), + new google.maps.LatLng(37.766103, -122.409268), + new google.maps.LatLng(37.766138, -122.409229), + new google.maps.LatLng(37.766183, -122.409231), + new google.maps.LatLng(37.766153, -122.409276), + new google.maps.LatLng(37.766005, -122.409365), + new google.maps.LatLng(37.765897, -122.40957), + new google.maps.LatLng(37.765767, -122.409739), + new google.maps.LatLng(37.765693, -122.410389), + new google.maps.LatLng(37.765615, -122.411201), + new google.maps.LatLng(37.765533, -122.412121), + new google.maps.LatLng(37.765467, -122.412939), + new google.maps.LatLng(37.765444, -122.414821), + new google.maps.LatLng(37.765444, -122.414964), + new google.maps.LatLng(37.765318, -122.415424), + new google.maps.LatLng(37.763961, -122.415296), + new google.maps.LatLng(37.763115, -122.415196), + new google.maps.LatLng(37.762967, -122.415183), + new google.maps.LatLng(37.762278, -122.415127), + new google.maps.LatLng(37.761675, -122.415055), + new google.maps.LatLng(37.760932, -122.414988), + new google.maps.LatLng(37.759337, -122.414862), + new google.maps.LatLng(37.773187, -122.421922), + new google.maps.LatLng(37.773043, -122.422118), + new google.maps.LatLng(37.773007, -122.422165), + new google.maps.LatLng(37.772979, -122.422219), + new google.maps.LatLng(37.772865, -122.422394), + new google.maps.LatLng(37.772779, -122.422503), + new google.maps.LatLng(37.772676, -122.422701), + new google.maps.LatLng(37.772606, -122.422806), + new google.maps.LatLng(37.772566, -122.42284), + new google.maps.LatLng(37.772508, -122.422852), + new google.maps.LatLng(37.772387, -122.423011), + new google.maps.LatLng(37.772099, -122.423328), + new google.maps.LatLng(37.771704, -122.423783), + new google.maps.LatLng(37.771481, -122.424081), + new google.maps.LatLng(37.7714, -122.424179), + new google.maps.LatLng(37.771352, -122.42422), + new google.maps.LatLng(37.771248, -122.424327), + new google.maps.LatLng(37.770904, -122.424781), + new google.maps.LatLng(37.77052, -122.425283), + new google.maps.LatLng(37.770337, -122.425553), + new google.maps.LatLng(37.770128, -122.425832), + new google.maps.LatLng(37.769756, -122.426331), + new google.maps.LatLng(37.7693, -122.426902), + new google.maps.LatLng(37.769132, -122.427065), + new google.maps.LatLng(37.769092, -122.427103), + new google.maps.LatLng(37.768979, -122.427172), + new google.maps.LatLng(37.768595, -122.427634), + new google.maps.LatLng(37.768372, -122.427913), + new google.maps.LatLng(37.768337, -122.427961), + new google.maps.LatLng(37.768244, -122.428138), + new google.maps.LatLng(37.767942, -122.428581), + new google.maps.LatLng(37.767482, -122.429094), + new google.maps.LatLng(37.767031, -122.429606), + new google.maps.LatLng(37.766732, -122.429986), + new google.maps.LatLng(37.76668, -122.430058), + new google.maps.LatLng(37.766633, -122.430109), + new google.maps.LatLng(37.76658, -122.430211), + new google.maps.LatLng(37.766367, -122.430594), + new google.maps.LatLng(37.76591, -122.431137), + new google.maps.LatLng(37.765353, -122.431806), + new google.maps.LatLng(37.764962, -122.432298), + new google.maps.LatLng(37.764868, -122.432486), + new google.maps.LatLng(37.764518, -122.432913), + new google.maps.LatLng(37.763435, -122.434173), + new google.maps.LatLng(37.762847, -122.434953), + new google.maps.LatLng(37.762291, -122.435935), + new google.maps.LatLng(37.762224, -122.436074), + new google.maps.LatLng(37.761957, -122.436892), + new google.maps.LatLng(37.761652, -122.438886), + new google.maps.LatLng(37.761284, -122.439955), + new google.maps.LatLng(37.76121, -122.440068), + new google.maps.LatLng(37.761064, -122.44072), + new google.maps.LatLng(37.76104, -122.441411), + new google.maps.LatLng(37.761048, -122.442324), + new google.maps.LatLng(37.760851, -122.443118), + new google.maps.LatLng(37.759977, -122.444591), + new google.maps.LatLng(37.759913, -122.444698), + new google.maps.LatLng(37.759623, -122.445065), + new google.maps.LatLng(37.758902, -122.445158), + new google.maps.LatLng(37.758428, -122.44457), + new google.maps.LatLng(37.757687, -122.44334), + new google.maps.LatLng(37.757583, -122.44324), + new google.maps.LatLng(37.757019, -122.442787), + new google.maps.LatLng(37.756603, -122.442322), + new google.maps.LatLng(37.75638, -122.441602), + new google.maps.LatLng(37.75579, -122.441382), + new google.maps.LatLng(37.754493, -122.442133), + new google.maps.LatLng(37.754361, -122.442206), + new google.maps.LatLng(37.753719, -122.44265), + new google.maps.LatLng(37.753096, -122.442915), + new google.maps.LatLng(37.751617, -122.443211), + new google.maps.LatLng(37.751496, -122.443246), + new google.maps.LatLng(37.750733, -122.443428), + new google.maps.LatLng(37.750126, -122.443536), + new google.maps.LatLng(37.750103, -122.443784), + new google.maps.LatLng(37.75039, -122.44401), + new google.maps.LatLng(37.750448, -122.444013), + new google.maps.LatLng(37.750536, -122.44404), + new google.maps.LatLng(37.750493, -122.444141), + new google.maps.LatLng(37.790859, -122.402808), + new google.maps.LatLng(37.790864, -122.402768), + new google.maps.LatLng(37.790995, -122.402539), + new google.maps.LatLng(37.791148, -122.402172), + new google.maps.LatLng(37.791385, -122.401312), + new google.maps.LatLng(37.791405, -122.400776), + new google.maps.LatLng(37.791288, -122.400528), + new google.maps.LatLng(37.791113, -122.400441), + new google.maps.LatLng(37.791027, -122.400395), + new google.maps.LatLng(37.791094, -122.400311), + new google.maps.LatLng(37.791211, -122.400183), + new google.maps.LatLng(37.79106, -122.399334), + new google.maps.LatLng(37.790538, -122.398718), + new google.maps.LatLng(37.790095, -122.398086), + new google.maps.LatLng(37.789644, -122.39736), + new google.maps.LatLng(37.789254, -122.396844), + new google.maps.LatLng(37.788855, -122.396397), + new google.maps.LatLng(37.788483, -122.395963), + new google.maps.LatLng(37.788015, -122.395365), + new google.maps.LatLng(37.787558, -122.394735), + new google.maps.LatLng(37.787472, -122.394323), + new google.maps.LatLng(37.78763, -122.394025), + new google.maps.LatLng(37.787767, -122.393987), + new google.maps.LatLng(37.787486, -122.394452), + new google.maps.LatLng(37.786977, -122.395043), + new google.maps.LatLng(37.786583, -122.395552), + new google.maps.LatLng(37.78654, -122.39561), + new google.maps.LatLng(37.786516, -122.395659), + new google.maps.LatLng(37.786378, -122.395707), + new google.maps.LatLng(37.786044, -122.395362), + new google.maps.LatLng(37.785598, -122.394715), + new google.maps.LatLng(37.785321, -122.394361), + new google.maps.LatLng(37.785207, -122.394236), + new google.maps.LatLng(37.785751, -122.394062), + new google.maps.LatLng(37.785996, -122.393881), + new google.maps.LatLng(37.786092, -122.39383), + new google.maps.LatLng(37.785998, -122.393899), + new google.maps.LatLng(37.785114, -122.394365), + new google.maps.LatLng(37.785022, -122.394441), + new google.maps.LatLng(37.784823, -122.394635), + new google.maps.LatLng(37.784719, -122.394629), + new google.maps.LatLng(37.785069, -122.394176), + new google.maps.LatLng(37.7855, -122.39365), + new google.maps.LatLng(37.78577, -122.393291), + new google.maps.LatLng(37.785839, -122.393159), + new google.maps.LatLng(37.782651, -122.400628), + new google.maps.LatLng(37.782616, -122.400599), + new google.maps.LatLng(37.782702, -122.40047), + new google.maps.LatLng(37.782915, -122.400192), + new google.maps.LatLng(37.783137, -122.399887), + new google.maps.LatLng(37.783414, -122.399519), + new google.maps.LatLng(37.783629, -122.399237), + new google.maps.LatLng(37.783688, -122.399157), + new google.maps.LatLng(37.783716, -122.399106), + new google.maps.LatLng(37.783798, -122.399072), + new google.maps.LatLng(37.783997, -122.399186), + new google.maps.LatLng(37.784271, -122.399538), + new google.maps.LatLng(37.784577, -122.399948), + new google.maps.LatLng(37.784828, -122.40026), + new google.maps.LatLng(37.784999, -122.400477), + new google.maps.LatLng(37.785113, -122.400651), + new google.maps.LatLng(37.785155, -122.400703), + new google.maps.LatLng(37.785192, -122.400749), + new google.maps.LatLng(37.785278, -122.400839), + new google.maps.LatLng(37.785387, -122.400857), + new google.maps.LatLng(37.785478, -122.40089), + new google.maps.LatLng(37.785526, -122.401022), + new google.maps.LatLng(37.785598, -122.401148), + new google.maps.LatLng(37.785631, -122.401202), + new google.maps.LatLng(37.78566, -122.401267), + new google.maps.LatLng(37.803986, -122.426035), + new google.maps.LatLng(37.804102, -122.425089), + new google.maps.LatLng(37.804211, -122.424156), + new google.maps.LatLng(37.803861, -122.423385), + new google.maps.LatLng(37.803151, -122.423214), + new google.maps.LatLng(37.802439, -122.423077), + new google.maps.LatLng(37.80174, -122.422905), + new google.maps.LatLng(37.801069, -122.422785), + new google.maps.LatLng(37.800345, -122.422649), + new google.maps.LatLng(37.799633, -122.422603), + new google.maps.LatLng(37.79975, -122.4217), + new google.maps.LatLng(37.799885, -122.420854), + new google.maps.LatLng(37.799209, -122.420607), + new google.maps.LatLng(37.795656, -122.400395), + new google.maps.LatLng(37.795203, -122.400304), + new google.maps.LatLng(37.778738, -122.415584), + new google.maps.LatLng(37.778812, -122.415189), + new google.maps.LatLng(37.778824, -122.415092), + new google.maps.LatLng(37.778833, -122.414932), + new google.maps.LatLng(37.778834, -122.414898), + new google.maps.LatLng(37.77874, -122.414757), + new google.maps.LatLng(37.778501, -122.414433), + new google.maps.LatLng(37.778182, -122.414026), + new google.maps.LatLng(37.777851, -122.413623), + new google.maps.LatLng(37.777486, -122.413166), + new google.maps.LatLng(37.777109, -122.412674), + new google.maps.LatLng(37.776743, -122.412186), + new google.maps.LatLng(37.77644, -122.4118), + new google.maps.LatLng(37.776295, -122.411614), + new google.maps.LatLng(37.776158, -122.41144), + new google.maps.LatLng(37.775806, -122.410997), + new google.maps.LatLng(37.775422, -122.410484), + new google.maps.LatLng(37.775126, -122.410087), + new google.maps.LatLng(37.775012, -122.409854), + new google.maps.LatLng(37.775164, -122.409573), + new google.maps.LatLng(37.775498, -122.40918), + new google.maps.LatLng(37.775868, -122.40873), + new google.maps.LatLng(37.776256, -122.40824), + new google.maps.LatLng(37.776519, -122.407928), + new google.maps.LatLng(37.776539, -122.407904), + new google.maps.LatLng(37.776595, -122.407854), + new google.maps.LatLng(37.776853, -122.407547), + new google.maps.LatLng(37.777234, -122.407087), + new google.maps.LatLng(37.777644, -122.406558), + new google.maps.LatLng(37.778066, -122.406017), + new google.maps.LatLng(37.778468, -122.405499), + new google.maps.LatLng(37.778866, -122.404995), + new google.maps.LatLng(37.779295, -122.404455), + new google.maps.LatLng(37.779695, -122.40395), + new google.maps.LatLng(37.779982, -122.403584), + new google.maps.LatLng(37.780295, -122.403223), + new google.maps.LatLng(37.780664, -122.402766), + new google.maps.LatLng(37.781043, -122.402288), + new google.maps.LatLng(37.781399, -122.401823), + new google.maps.LatLng(37.781727, -122.401407), + new google.maps.LatLng(37.781853, -122.401247), + new google.maps.LatLng(37.781894, -122.401195), + new google.maps.LatLng(37.782076, -122.400977), + new google.maps.LatLng(37.782338, -122.400603), + new google.maps.LatLng(37.782666, -122.400133), + new google.maps.LatLng(37.783048, -122.399634), + new google.maps.LatLng(37.78345, -122.399198), + new google.maps.LatLng(37.783791, -122.398998), + new google.maps.LatLng(37.784177, -122.398959), + new google.maps.LatLng(37.784388, -122.398971), + new google.maps.LatLng(37.784404, -122.399128), + new google.maps.LatLng(37.784586, -122.399524), + new google.maps.LatLng(37.784835, -122.399927), + new google.maps.LatLng(37.785116, -122.400307), + new google.maps.LatLng(37.785282, -122.400539), + new google.maps.LatLng(37.785346, -122.400692), + new google.maps.LatLng(37.765769, -122.407201), + new google.maps.LatLng(37.76579, -122.407414), + new google.maps.LatLng(37.765802, -122.407755), + new google.maps.LatLng(37.765791, -122.408219), + new google.maps.LatLng(37.765763, -122.408759), + new google.maps.LatLng(37.765726, -122.409348), + new google.maps.LatLng(37.765716, -122.409882), + new google.maps.LatLng(37.765708, -122.410202), + new google.maps.LatLng(37.765705, -122.410253), + new google.maps.LatLng(37.765707, -122.410369), + new google.maps.LatLng(37.765692, -122.41072), + new google.maps.LatLng(37.765699, -122.411215), + new google.maps.LatLng(37.765687, -122.411789), + new google.maps.LatLng(37.765666, -122.412373), + new google.maps.LatLng(37.765598, -122.412883), + new google.maps.LatLng(37.765543, -122.413039), + new google.maps.LatLng(37.765532, -122.413125), + new google.maps.LatLng(37.7655, -122.413553), + new google.maps.LatLng(37.765448, -122.414053), + new google.maps.LatLng(37.765388, -122.414645), + new google.maps.LatLng(37.765323, -122.41525), + new google.maps.LatLng(37.765303, -122.415847), + new google.maps.LatLng(37.765251, -122.416439), + new google.maps.LatLng(37.765204, -122.41702), + new google.maps.LatLng(37.765172, -122.417556), + new google.maps.LatLng(37.765164, -122.418075), + new google.maps.LatLng(37.765153, -122.418618), + new google.maps.LatLng(37.765136, -122.419112), + new google.maps.LatLng(37.765129, -122.419378), + new google.maps.LatLng(37.765119, -122.419481), + new google.maps.LatLng(37.7651, -122.419852), + new google.maps.LatLng(37.765083, -122.420349), + new google.maps.LatLng(37.765045, -122.42093), + new google.maps.LatLng(37.764992, -122.421481), + new google.maps.LatLng(37.76498, -122.421695), + new google.maps.LatLng(37.764993, -122.421843), + new google.maps.LatLng(37.764986, -122.422255), + new google.maps.LatLng(37.764975, -122.422823), + new google.maps.LatLng(37.764939, -122.423411), + new google.maps.LatLng(37.764902, -122.424014), + new google.maps.LatLng(37.764853, -122.424576), + new google.maps.LatLng(37.764826, -122.424922), + new google.maps.LatLng(37.764796, -122.425375), + new google.maps.LatLng(37.764782, -122.425869), + new google.maps.LatLng(37.764768, -122.426089), + new google.maps.LatLng(37.764766, -122.426117), + new google.maps.LatLng(37.764723, -122.426276), + new google.maps.LatLng(37.764681, -122.426649), + new google.maps.LatLng(37.782012, -122.4042), + new google.maps.LatLng(37.781574, -122.404911), + new google.maps.LatLng(37.781055, -122.405597), + new google.maps.LatLng(37.780479, -122.406341), + new google.maps.LatLng(37.779996, -122.406939), + new google.maps.LatLng(37.779459, -122.407613), + new google.maps.LatLng(37.778953, -122.408228), + new google.maps.LatLng(37.778409, -122.408839), + new google.maps.LatLng(37.777842, -122.409501), + new google.maps.LatLng(37.777334, -122.410181), + new google.maps.LatLng(37.776809, -122.410836), + new google.maps.LatLng(37.77624, -122.411514), + new google.maps.LatLng(37.775725, -122.412145), + new google.maps.LatLng(37.77519, -122.412805), + new google.maps.LatLng(37.774672, -122.413464), + new google.maps.LatLng(37.774084, -122.414186), + new google.maps.LatLng(37.773533, -122.413636), + new google.maps.LatLng(37.773021, -122.413009), + new google.maps.LatLng(37.772501, -122.412371), + new google.maps.LatLng(37.771964, -122.411681), + new google.maps.LatLng(37.771479, -122.411078), + new google.maps.LatLng(37.770992, -122.410477), + new google.maps.LatLng(37.770467, -122.409801), + new google.maps.LatLng(37.77009, -122.408904), + new google.maps.LatLng(37.769657, -122.408103), + new google.maps.LatLng(37.769132, -122.407276), + new google.maps.LatLng(37.768564, -122.406469), + new google.maps.LatLng(37.76798, -122.405745), + new google.maps.LatLng(37.76738, -122.405299), + new google.maps.LatLng(37.766604, -122.405297), + new google.maps.LatLng(37.765838, -122.4052), + new google.maps.LatLng(37.765139, -122.405139), + new google.maps.LatLng(37.764457, -122.405094), + new google.maps.LatLng(37.763716, -122.405142), + new google.maps.LatLng(37.762932, -122.405398), + new google.maps.LatLng(37.762126, -122.405813), + new google.maps.LatLng(37.761344, -122.406215), + new google.maps.LatLng(37.760556, -122.406495), + new google.maps.LatLng(37.759732, -122.406484), + new google.maps.LatLng(37.75891, -122.406228), + new google.maps.LatLng(37.758182, -122.405695), + new google.maps.LatLng(37.757676, -122.405118), + new google.maps.LatLng(37.757039, -122.404346), + new google.maps.LatLng(37.756335, -122.403719), + new google.maps.LatLng(37.755503, -122.403406), + new google.maps.LatLng(37.754665, -122.403242), + new google.maps.LatLng(37.753837, -122.403172), + new google.maps.LatLng(37.752986, -122.403112), + new google.maps.LatLng(37.751266, -122.403355), + ]; +} +// [END maps_layer_heatmap] +export { initMap }; diff --git a/Birdmap.API/ClientApp/src/components/heatmap/heatmap.tsx b/Birdmap.API/ClientApp/src/components/heatmap/heatmap.tsx new file mode 100644 index 0000000..5d7a8b8 --- /dev/null +++ b/Birdmap.API/ClientApp/src/components/heatmap/heatmap.tsx @@ -0,0 +1,21 @@ +import { Map, GoogleApiWrapper } from 'google-maps-react'; + +export function Heatmap() { + const mapStyles = { + width: '100%', + height: '100%', + }; + + return ( + + ); +} + +export default GoogleApiWrapper({ + apiKey: 'AIzaSyCZ51VFfxqZ2GkCmVrcNZdUKsM0fuBQUCY' +}); \ No newline at end of file diff --git a/Birdmap.API/Controllers/AuthController.cs b/Birdmap.API/Controllers/AuthController.cs index 76d6872..4105a9e 100644 --- a/Birdmap.API/Controllers/AuthController.cs +++ b/Birdmap.API/Controllers/AuthController.cs @@ -35,8 +35,7 @@ namespace Birdmap.Controllers } [AllowAnonymous] - [HttpPost("authenticate")] - [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] + [HttpPost("authenticate"), ProducesResponseType(typeof(object), StatusCodes.Status200OK)] public async Task AuthenticateAsync([FromBody] AuthenticateRequest model) { _logger.LogInformation($"Authenticating user [{model.Username}] with password [*******]..."); @@ -70,8 +69,7 @@ namespace Birdmap.Controllers } [AllowAnonymous] - [HttpPost("register")] - [ProducesResponseType(StatusCodes.Status204NoContent)] + [HttpPost("register"), ProducesResponseType(StatusCodes.Status204NoContent)] public async Task RegisterAsync([FromBody] RegisterRequest model) { _logger.LogInformation($"Registering user [{model.Username}]..."); diff --git a/Birdmap.API/Controllers/DevicesController.cs b/Birdmap.API/Controllers/DevicesController.cs new file mode 100644 index 0000000..2791598 --- /dev/null +++ b/Birdmap.API/Controllers/DevicesController.cs @@ -0,0 +1,144 @@ +using Birdmap.BLL.Interfaces; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System; +using System.Threading.Tasks; +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using System.Linq; +using Microsoft.AspNetCore.Authorization; + +namespace Birdmap.API.Controllers +{ + [Authorize] + [ApiController] + [Route("api/[controller]")] + public class DevicesController : ControllerBase + { + private readonly IDeviceService _service; + private readonly ILogger _logger; + + public DevicesController(IDeviceService service, ILogger logger) + { + _service = service; + _logger = logger; + } + + /// Get all device info + /// Array of devices + [HttpGet] + public async Task>> Getall() + { + _logger.LogInformation("Getting all devices..."); + + return (await _service.GetallAsync()).ToList(); + } + + /// Shut down all devices + /// Message sent + [HttpPost, Route("offline")] + public async Task Offlineall() + { + _logger.LogInformation("Turning off all devices and sensors..."); + + await _service.OfflineallAsync(); + + return Ok(); + } + + /// Bring all devices online + /// Message sent + [HttpPost, Route("online")] + public async Task Onlineall() + { + _logger.LogInformation("Turning on all devices and sensors..."); + + await _service.OnlineallAsync(); + + return Ok(); + } + + /// Get all device info + /// ID of device to query + /// Information about a particular device + [HttpGet, Route("{deviceID}")] + public async Task> Getdevice([BindRequired] Guid deviceID) + { + _logger.LogInformation($"Getting device [{deviceID}]..."); + + return await _service.GetdeviceAsync(deviceID); + } + + /// Shut down device + /// ID of device to shut down + /// Message sent + [HttpPost, Route("{deviceID}/offline")] + public async Task Offlinedevice([BindRequired] Guid deviceID) + { + _logger.LogInformation($"Turning off device [{deviceID}]..."); + + await _service.OfflinedeviceAsync(deviceID); + + return Ok(); + } + + /// Bring device online + /// ID of device to bring online + /// Message sent + [HttpPost, Route("{deviceID}/online")] + public async Task Onlinedevice([BindRequired] Guid deviceID) + { + _logger.LogInformation($"Turning on device [{deviceID}]..."); + + await _service.OnlinedeviceAsync(deviceID); + + return Ok(); + } + + /// Get info about a particular device's sensor + /// ID of device to query + /// ID of sensor to query + /// Information about a sensor + [HttpGet, Route("{deviceID}/{sensorID}")] + public async Task> Getsensor([BindRequired] Guid deviceID, [BindRequired] Guid sensorID) + { + _logger.LogInformation($"Getting sensor [{sensorID}] of device [{deviceID}]..."); + + return await _service.GetsensorAsync(deviceID, sensorID); + } + + /// Shut down sensor + /// ID of device to query + /// ID of sensor to query + /// Message sent + [HttpPost, Route("{deviceID}/{sensorID}/offline")] + public async Task Offlinesensor([BindRequired] Guid deviceID, [BindRequired] Guid sensorID) + { + _logger.LogInformation($"Turning off sensor [{sensorID}] of device [{deviceID}]..."); + + await _service.OfflinesensorAsync(deviceID, sensorID); + + return Ok(); + } + + /// Bring sensor online + /// ID of device to query + /// ID of sensor to query + /// Message sent + [HttpPost, Route("{deviceID}/{sensorID}/online")] + public async Task Onlinesensor([BindRequired] Guid deviceID, [BindRequired] Guid sensorID) + { + _logger.LogInformation($"Turning on sensor [{sensorID}] of device [{deviceID}]..."); + + await _service.OnlinesensorAsync(deviceID, sensorID); + + return Ok(); + } + } +} + +#pragma warning restore 1591 +#pragma warning restore 1573 +#pragma warning restore 472 +#pragma warning restore 114 +#pragma warning restore 108 \ No newline at end of file diff --git a/Birdmap.API/Controllers/ServicesController.cs b/Birdmap.API/Controllers/ServicesController.cs index d60e28c..6da1729 100644 --- a/Birdmap.API/Controllers/ServicesController.cs +++ b/Birdmap.API/Controllers/ServicesController.cs @@ -30,8 +30,7 @@ namespace Birdmap.API.Controllers _logger = logger; } - [HttpGet] - [ProducesResponseType(StatusCodes.Status200OK)] + [HttpGet, ProducesResponseType(StatusCodes.Status200OK)] public async Task>> GetAsync() { _logger.LogInformation($"Getting all services from db..."); @@ -59,8 +58,7 @@ namespace Birdmap.API.Controllers return serviceInfos.ToList(); } - [HttpPost] - [ProducesResponseType(StatusCodes.Status201Created)] + [HttpPost, ProducesResponseType(StatusCodes.Status201Created)] public async Task> PostAsync(ServiceRequest request) { _logger.LogInformation($"Creating service [{request.Name}]..."); @@ -74,8 +72,7 @@ namespace Birdmap.API.Controllers _mapper.Map(created)); } - [HttpPut] - [ProducesResponseType(StatusCodes.Status204NoContent)] + [HttpPut, ProducesResponseType(StatusCodes.Status204NoContent)] public async Task PutAsync(ServiceRequest request) { _logger.LogInformation($"Updating service [{request.Name}]..."); @@ -87,8 +84,7 @@ namespace Birdmap.API.Controllers return NoContent(); } - [HttpDelete("{id}")] - [ProducesResponseType(StatusCodes.Status204NoContent)] + [HttpDelete("{id}"), ProducesResponseType(StatusCodes.Status204NoContent)] public async Task DeleteAsync(int id) { _logger.LogInformation($"Deleting service [{id}]..."); diff --git a/Birdmap.API/appsettings.json b/Birdmap.API/appsettings.json index f774618..fe9b2e1 100644 --- a/Birdmap.API/appsettings.json +++ b/Birdmap.API/appsettings.json @@ -27,5 +27,6 @@ "Role": "User" } ] - } + }, + "UseDummyServices": true } diff --git a/Birdmap.BLL/Interfaces/IDeviceService.cs b/Birdmap.BLL/Interfaces/IDeviceService.cs new file mode 100644 index 0000000..047c619 --- /dev/null +++ b/Birdmap.BLL/Interfaces/IDeviceService.cs @@ -0,0 +1,279 @@ +namespace Birdmap.BLL.Interfaces +{ + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")] + public partial class ListOfDevices : System.Collections.ObjectModel.Collection + { + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")] + public partial class Device + { + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Guid Id { get; set; } + + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public DeviceStatus Status { get; set; } + + [Newtonsoft.Json.JsonProperty("url", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Url { get; set; } + + [Newtonsoft.Json.JsonProperty("coordinates", Required = Newtonsoft.Json.Required.AllowNull)] + [System.ComponentModel.DataAnnotations.Required] + public Coordinates Coordinates { get; set; } = new Coordinates(); + + [Newtonsoft.Json.JsonProperty("sensors", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public ArrayofSensors Sensors { get; set; } = new ArrayofSensors(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")] + public partial class ArrayofSensors : System.Collections.ObjectModel.Collection + { + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")] + public partial class Sensor + { + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Guid Id { get; set; } + + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public SensorStatus Status { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")] + public partial class Coordinates + { + [Newtonsoft.Json.JsonProperty("latitude", Required = Newtonsoft.Json.Required.Always)] + public double Latitude { get; set; } + + [Newtonsoft.Json.JsonProperty("longitude", Required = Newtonsoft.Json.Required.Always)] + public double Longitude { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")] + public enum DeviceStatus + { + [System.Runtime.Serialization.EnumMember(Value = @"online")] + Online = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"error")] + Error = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"offline")] + Offline = 2, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")] + public enum SensorStatus + { + [System.Runtime.Serialization.EnumMember(Value = @"online")] + Online = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"unknown")] + Unknown = 1, + + [System.Runtime.Serialization.EnumMember(Value = @"offline")] + Offline = 2, + + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0))")] + public partial class ApiException : System.Exception + { + public int StatusCode { get; private set; } + + public string Response { get; private set; } + + public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } + + public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception innerException) + : base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) + { + StatusCode = statusCode; + Response = response; + Headers = headers; + } + + public override string ToString() + { + return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString()); + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0))")] + public partial class ApiException : ApiException + { + public TResult Result { get; private set; } + + public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception innerException) + : base(message, statusCode, response, headers, innerException) + { + Result = result; + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0))")] + public partial interface IDeviceService + { + /// Get all device info + /// Array of devices + /// A server side error occurred. + System.Threading.Tasks.Task> GetallAsync(); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Get all device info + /// Array of devices + /// A server side error occurred. + System.Threading.Tasks.Task> GetallAsync(System.Threading.CancellationToken cancellationToken); + + /// Shut down all devices + /// Message sent + /// A server side error occurred. + System.Threading.Tasks.Task OfflineallAsync(); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Shut down all devices + /// Message sent + /// A server side error occurred. + System.Threading.Tasks.Task OfflineallAsync(System.Threading.CancellationToken cancellationToken); + + /// Bring all devices online + /// Message sent + /// A server side error occurred. + System.Threading.Tasks.Task OnlineallAsync(); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Bring all devices online + /// Message sent + /// A server side error occurred. + System.Threading.Tasks.Task OnlineallAsync(System.Threading.CancellationToken cancellationToken); + + /// Get all device info + /// ID of device to query + /// Information about a particular device + /// A server side error occurred. + System.Threading.Tasks.Task GetdeviceAsync(System.Guid deviceID); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Get all device info + /// ID of device to query + /// Information about a particular device + /// A server side error occurred. + System.Threading.Tasks.Task GetdeviceAsync(System.Guid deviceID, System.Threading.CancellationToken cancellationToken); + + /// Shut down device + /// ID of device to shut down + /// Message sent + /// A server side error occurred. + System.Threading.Tasks.Task OfflinedeviceAsync(System.Guid deviceID); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Shut down device + /// ID of device to shut down + /// Message sent + /// A server side error occurred. + System.Threading.Tasks.Task OfflinedeviceAsync(System.Guid deviceID, System.Threading.CancellationToken cancellationToken); + + /// Bring device online + /// ID of device to bring online + /// Message sent + /// A server side error occurred. + System.Threading.Tasks.Task OnlinedeviceAsync(System.Guid deviceID); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Bring device online + /// ID of device to bring online + /// Message sent + /// A server side error occurred. + System.Threading.Tasks.Task OnlinedeviceAsync(System.Guid deviceID, System.Threading.CancellationToken cancellationToken); + + /// Get info about a particular device's sensor + /// ID of device to query + /// ID of sensor to query + /// Information about a sensor + /// A server side error occurred. + System.Threading.Tasks.Task GetsensorAsync(System.Guid deviceID, System.Guid sensorID); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Get info about a particular device's sensor + /// ID of device to query + /// ID of sensor to query + /// Information about a sensor + /// A server side error occurred. + System.Threading.Tasks.Task GetsensorAsync(System.Guid deviceID, System.Guid sensorID, System.Threading.CancellationToken cancellationToken); + + /// Shut down sensor + /// ID of device to query + /// ID of sensor to query + /// Message sent + /// A server side error occurred. + System.Threading.Tasks.Task OfflinesensorAsync(System.Guid deviceID, System.Guid sensorID); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Shut down sensor + /// ID of device to query + /// ID of sensor to query + /// Message sent + /// A server side error occurred. + System.Threading.Tasks.Task OfflinesensorAsync(System.Guid deviceID, System.Guid sensorID, System.Threading.CancellationToken cancellationToken); + + /// Bring sensor online + /// ID of device to query + /// ID of sensor to query + /// Message sent + /// A server side error occurred. + System.Threading.Tasks.Task OnlinesensorAsync(System.Guid deviceID, System.Guid sensorID); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Bring sensor online + /// ID of device to query + /// ID of sensor to query + /// Message sent + /// A server side error occurred. + System.Threading.Tasks.Task OnlinesensorAsync(System.Guid deviceID, System.Guid sensorID, System.Threading.CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/Birdmap.BLL/Services/DeviceServiceBase.cs b/Birdmap.BLL/Services/DeviceServiceBase.cs new file mode 100644 index 0000000..aeab79d --- /dev/null +++ b/Birdmap.BLL/Services/DeviceServiceBase.cs @@ -0,0 +1,39 @@ +using Birdmap.BLL.Interfaces; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Birdmap.BLL.Services +{ + public abstract class DeviceServiceBase : IDeviceService + { + public virtual Task> GetallAsync() + => GetallAsync(CancellationToken.None); + public abstract Task> GetallAsync(CancellationToken cancellationToken); + public virtual Task GetdeviceAsync(Guid deviceID) + => GetdeviceAsync(deviceID, CancellationToken.None); + public abstract Task GetdeviceAsync(Guid deviceID, CancellationToken cancellationToken); + public virtual Task GetsensorAsync(Guid deviceID, Guid sensorID) + => GetsensorAsync(deviceID, sensorID, CancellationToken.None); + public abstract Task GetsensorAsync(Guid deviceID, Guid sensorID, CancellationToken cancellationToken); + public virtual Task OfflineallAsync() + => OfflineallAsync(CancellationToken.None); + public abstract Task OfflineallAsync(CancellationToken cancellationToken); + public virtual Task OfflinedeviceAsync(Guid deviceID) + => OfflinedeviceAsync(deviceID, CancellationToken.None); + public abstract Task OfflinedeviceAsync(Guid deviceID, CancellationToken cancellationToken); + public virtual Task OfflinesensorAsync(Guid deviceID, Guid sensorID) + => OfflinesensorAsync(deviceID, sensorID, CancellationToken.None); + public abstract Task OfflinesensorAsync(Guid deviceID, Guid sensorID, CancellationToken cancellationToken); + public virtual Task OnlineallAsync() + => OnlineallAsync(CancellationToken.None); + public abstract Task OnlineallAsync(CancellationToken cancellationToken); + public virtual Task OnlinedeviceAsync(Guid deviceID) + => OnlinedeviceAsync(deviceID, CancellationToken.None); + public abstract Task OnlinedeviceAsync(Guid deviceID, CancellationToken cancellationToken); + public virtual Task OnlinesensorAsync(Guid deviceID, Guid sensorID) + => OnlinesensorAsync(deviceID, sensorID, CancellationToken.None); + public abstract Task OnlinesensorAsync(Guid deviceID, Guid sensorID, CancellationToken cancellationToken); + } +} diff --git a/Birdmap.BLL/Services/DummyDeviceService.cs b/Birdmap.BLL/Services/DummyDeviceService.cs new file mode 100644 index 0000000..617a83a --- /dev/null +++ b/Birdmap.BLL/Services/DummyDeviceService.cs @@ -0,0 +1,139 @@ +using Birdmap.BLL.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Birdmap.BLL.Services +{ + public class DummyDeviceService : DeviceServiceBase + { + private const double centerLong = 21.469640; + private const double centerLat = 48.275939; + private const double radius = 0.000200; + + private readonly Lazy> _devices = new Lazy>(GenerateDevices); + private static ListOfDevices GenerateDevices() + { + var devices = new ListOfDevices(); + var rand = new Random(); + + T GetRandomEnum() + { + var values = Enum.GetValues(typeof(T)); + return (T)values.GetValue(rand.Next(values.Length)); + } + + double GetPlusMinus(double center, double radius) + { + return center - radius + rand.NextDouble() * radius * 2; + } + + for (int d = 0; d < 15; d++) + { + var sensors = new ArrayofSensors(); + for (int s = 0; s < rand.Next(1, 5); s++) + { + sensors.Add(new Sensor + { + Id = Guid.NewGuid(), + Status = GetRandomEnum(), + }); + } + + devices.Add(new Device + { + Id = Guid.NewGuid(), + Sensors = sensors, + Status = GetRandomEnum(), + Url = "dummyservice.device.url", + Coordinates = new Coordinates + { + Latitude = GetPlusMinus(centerLat, radius), + Longitude = GetPlusMinus(centerLong, radius), + } + }); + } + + return devices; + } + + public override Task> GetallAsync(CancellationToken cancellationToken) + { + return Task.FromResult(_devices.Value); + } + + public override Task GetdeviceAsync(Guid deviceID, CancellationToken cancellationToken) + { + return Task.FromResult(_devices.Value.SingleOrDefault(d => d.Id == deviceID)); + } + + public override Task GetsensorAsync(Guid deviceID, Guid sensorID, CancellationToken cancellationToken) + { + return Task.FromResult(_devices.Value.SingleOrDefault(d => d.Id == deviceID)?.Sensors.SingleOrDefault(s => s.Id == sensorID)); + } + + public override Task OfflineallAsync(CancellationToken cancellationToken) + { + SetStatus(DeviceStatus.Offline, SensorStatus.Offline); + + return Task.CompletedTask; + } + + public override Task OfflinedeviceAsync(Guid deviceID, CancellationToken cancellationToken) + { + SetDeviceStatus(deviceID, DeviceStatus.Offline); + return Task.CompletedTask; + } + + public override Task OfflinesensorAsync(Guid deviceID, Guid sensorID, CancellationToken cancellationToken) + { + SetSensorStatus(deviceID, sensorID, SensorStatus.Offline); + return Task.CompletedTask; + } + + public override Task OnlineallAsync(CancellationToken cancellationToken) + { + SetStatus(DeviceStatus.Online, SensorStatus.Online); + + return Task.CompletedTask; + } + + public override Task OnlinedeviceAsync(Guid deviceID, CancellationToken cancellationToken) + { + SetDeviceStatus(deviceID, DeviceStatus.Online); + return Task.CompletedTask; + } + + public override Task OnlinesensorAsync(Guid deviceID, Guid sensorID, CancellationToken cancellationToken) + { + SetSensorStatus(deviceID, sensorID, SensorStatus.Online); + return Task.CompletedTask; + } + + private void SetStatus(DeviceStatus deviceStatus, SensorStatus sensorStatus) + { + foreach (var device in _devices.Value) + { + device.Status = deviceStatus; + foreach (var sensor in device.Sensors) + { + sensor.Status = sensorStatus; + } + } + } + + private void SetDeviceStatus(Guid deviceID, DeviceStatus status) + { + var device = GetdeviceAsync(deviceID).Result; + device.Status = status; + } + + private void SetSensorStatus(Guid deviceId, Guid sensorID, SensorStatus status) + { + var sensor = GetsensorAsync(deviceId, sensorID).Result; + sensor.Status = status; + } + } +} diff --git a/Birdmap.BLL/Services/LiveDeviceService.cs b/Birdmap.BLL/Services/LiveDeviceService.cs new file mode 100644 index 0000000..eb423c3 --- /dev/null +++ b/Birdmap.BLL/Services/LiveDeviceService.cs @@ -0,0 +1,902 @@ +//---------------------- +// +// Generated using the NSwag toolchain v13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0)) (http://NSwag.org) +// +//---------------------- + +#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." +#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." +#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' +#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... +#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." + +namespace Birdmap.BLL.Services +{ + using Birdmap.BLL.Interfaces; + using System = global::System; + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0))")] + public partial class LiveDummyService : IDeviceService + { + private string _baseUrl = "https://birb.k8s.kmlabz.com"; + private System.Net.Http.HttpClient _httpClient; + private System.Lazy _settings; + + public LiveDummyService(System.Net.Http.HttpClient httpClient) + { + _httpClient = httpClient; + _settings = new System.Lazy(CreateSerializerSettings); + } + + private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() + { + var settings = new Newtonsoft.Json.JsonSerializerSettings(); + UpdateJsonSerializerSettings(settings); + return settings; + } + + public string BaseUrl + { + get { return _baseUrl; } + set { _baseUrl = value; } + } + + protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } } + + partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); + partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); + + /// Get all device info + /// Array of devices + /// A server side error occurred. + public System.Threading.Tasks.Task> GetallAsync() + { + return GetallAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Get all device info + /// Array of devices + /// A server side error occurred. + public async System.Threading.Tasks.Task> GetallAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + PrepareRequest(client_, request_, urlBuilder_); + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 404) + { + string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("No device found", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Shut down all devices + /// Message sent + /// A server side error occurred. + public System.Threading.Tasks.Task OfflineallAsync() + { + return OfflineallAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Shut down all devices + /// Message sent + /// A server side error occurred. + public async System.Threading.Tasks.Task OfflineallAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/offline"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + + PrepareRequest(client_, request_, urlBuilder_); + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 500) + { + string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Message sending unsuccessful", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Bring all devices online + /// Message sent + /// A server side error occurred. + public System.Threading.Tasks.Task OnlineallAsync() + { + return OnlineallAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Bring all devices online + /// Message sent + /// A server side error occurred. + public async System.Threading.Tasks.Task OnlineallAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/online"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + + PrepareRequest(client_, request_, urlBuilder_); + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 500) + { + string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Message sending unsuccessful", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Get all device info + /// ID of device to query + /// Information about a particular device + /// A server side error occurred. + public System.Threading.Tasks.Task GetdeviceAsync(System.Guid deviceID) + { + return GetdeviceAsync(deviceID, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Get all device info + /// ID of device to query + /// Information about a particular device + /// A server side error occurred. + public async System.Threading.Tasks.Task GetdeviceAsync(System.Guid deviceID, System.Threading.CancellationToken cancellationToken) + { + if (deviceID == null) + throw new System.ArgumentNullException("deviceID"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/{deviceID}"); + urlBuilder_.Replace("{deviceID}", System.Uri.EscapeDataString(ConvertToString(deviceID, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + PrepareRequest(client_, request_, urlBuilder_); + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 404) + { + string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Device not found", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Shut down device + /// ID of device to shut down + /// Message sent + /// A server side error occurred. + public System.Threading.Tasks.Task OfflinedeviceAsync(System.Guid deviceID) + { + return OfflinedeviceAsync(deviceID, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Shut down device + /// ID of device to shut down + /// Message sent + /// A server side error occurred. + public async System.Threading.Tasks.Task OfflinedeviceAsync(System.Guid deviceID, System.Threading.CancellationToken cancellationToken) + { + if (deviceID == null) + throw new System.ArgumentNullException("deviceID"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/{deviceID}/offline"); + urlBuilder_.Replace("{deviceID}", System.Uri.EscapeDataString(ConvertToString(deviceID, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + + PrepareRequest(client_, request_, urlBuilder_); + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 500) + { + string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Message sending unsuccessful", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Bring device online + /// ID of device to bring online + /// Message sent + /// A server side error occurred. + public System.Threading.Tasks.Task OnlinedeviceAsync(System.Guid deviceID) + { + return OnlinedeviceAsync(deviceID, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Bring device online + /// ID of device to bring online + /// Message sent + /// A server side error occurred. + public async System.Threading.Tasks.Task OnlinedeviceAsync(System.Guid deviceID, System.Threading.CancellationToken cancellationToken) + { + if (deviceID == null) + throw new System.ArgumentNullException("deviceID"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/{deviceID}/online"); + urlBuilder_.Replace("{deviceID}", System.Uri.EscapeDataString(ConvertToString(deviceID, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + + PrepareRequest(client_, request_, urlBuilder_); + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 500) + { + string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Message sending unsuccessful", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Get info about a particular device's sensor + /// ID of device to query + /// ID of sensor to query + /// Information about a sensor + /// A server side error occurred. + public System.Threading.Tasks.Task GetsensorAsync(System.Guid deviceID, System.Guid sensorID) + { + return GetsensorAsync(deviceID, sensorID, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Get info about a particular device's sensor + /// ID of device to query + /// ID of sensor to query + /// Information about a sensor + /// A server side error occurred. + public async System.Threading.Tasks.Task GetsensorAsync(System.Guid deviceID, System.Guid sensorID, System.Threading.CancellationToken cancellationToken) + { + if (deviceID == null) + throw new System.ArgumentNullException("deviceID"); + + if (sensorID == null) + throw new System.ArgumentNullException("sensorID"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/{deviceID}/{sensorID}"); + urlBuilder_.Replace("{deviceID}", System.Uri.EscapeDataString(ConvertToString(deviceID, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Replace("{sensorID}", System.Uri.EscapeDataString(ConvertToString(sensorID, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + PrepareRequest(client_, request_, urlBuilder_); + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 404) + { + string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Device or sensor not found", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Shut down sensor + /// ID of device to query + /// ID of sensor to query + /// Message sent + /// A server side error occurred. + public System.Threading.Tasks.Task OfflinesensorAsync(System.Guid deviceID, System.Guid sensorID) + { + return OfflinesensorAsync(deviceID, sensorID, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Shut down sensor + /// ID of device to query + /// ID of sensor to query + /// Message sent + /// A server side error occurred. + public async System.Threading.Tasks.Task OfflinesensorAsync(System.Guid deviceID, System.Guid sensorID, System.Threading.CancellationToken cancellationToken) + { + if (deviceID == null) + throw new System.ArgumentNullException("deviceID"); + + if (sensorID == null) + throw new System.ArgumentNullException("sensorID"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/{deviceID}/{sensorID}/offline"); + urlBuilder_.Replace("{deviceID}", System.Uri.EscapeDataString(ConvertToString(deviceID, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Replace("{sensorID}", System.Uri.EscapeDataString(ConvertToString(sensorID, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + + PrepareRequest(client_, request_, urlBuilder_); + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 500) + { + string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Message sending unsuccessful", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Bring sensor online + /// ID of device to query + /// ID of sensor to query + /// Message sent + /// A server side error occurred. + public System.Threading.Tasks.Task OnlinesensorAsync(System.Guid deviceID, System.Guid sensorID) + { + return OnlinesensorAsync(deviceID, sensorID, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Bring sensor online + /// ID of device to query + /// ID of sensor to query + /// Message sent + /// A server side error occurred. + public async System.Threading.Tasks.Task OnlinesensorAsync(System.Guid deviceID, System.Guid sensorID, System.Threading.CancellationToken cancellationToken) + { + if (deviceID == null) + throw new System.ArgumentNullException("deviceID"); + + if (sensorID == null) + throw new System.ArgumentNullException("sensorID"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/devices/{deviceID}/{sensorID}/online"); + urlBuilder_.Replace("{deviceID}", System.Uri.EscapeDataString(ConvertToString(deviceID, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Replace("{sensorID}", System.Uri.EscapeDataString(ConvertToString(sensorID, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + + PrepareRequest(client_, request_, urlBuilder_); + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 500) + { + string responseText_ = (response_.Content == null) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("Message sending unsuccessful", status_, responseText_, headers_, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T), string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody, responseText); + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using (var streamReader = new System.IO.StreamReader(responseStream)) + using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) + { + var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); + var typedBody = serializer.Deserialize(jsonTextReader); + return new ObjectResponseResult(typedBody, string.Empty); + } + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return null; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + return System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[])value); + } + else if (value.GetType().IsArray) + { + var array = System.Linq.Enumerable.OfType((System.Array)value); + return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo))); + } + + var result = System.Convert.ToString(value, cultureInfo); + return (result is null) ? string.Empty : result; + } + } +} + +#pragma warning restore 1591 +#pragma warning restore 1573 +#pragma warning restore 472 +#pragma warning restore 114 +#pragma warning restore 108 \ No newline at end of file diff --git a/Birdmap.BLL/Startup.cs b/Birdmap.BLL/Startup.cs index a3b9480..698db11 100644 --- a/Birdmap.BLL/Startup.cs +++ b/Birdmap.BLL/Startup.cs @@ -13,6 +13,11 @@ namespace Birdmap.BLL services.AddTransient(); services.AddTransient(); + if (configuration.GetValue("UseDummyServices")) + services.AddTransient(); + else + services.AddTransient(); + return services; } } diff --git a/c-n-c-nswag.nswag b/c-n-c-nswag.nswag new file mode 100644 index 0000000..87f9a5c --- /dev/null +++ b/c-n-c-nswag.nswag @@ -0,0 +1,221 @@ +{ + "runtime": "NetCore31", + "defaultVariables": null, + "documentGenerator": { + "fromDocument": { + "json": "openapi: 3.0.3\ninfo:\n title: Command and Control Service\n description: This service s responsible for controlling and handling information\n about IoT devices in the Birbnetes system.\n contact:\n email: tormakristof@tormakristof.eu\n license:\n name: Apache 2.0\n url: http://www.apache.org/licenses/LICENSE-2.0.html\n version: 1.0.0\nservers:\n- url: https://birb.k8s.kmlabz.com\ntags:\n- name: cnc\n description: Command and Control Service interaction\npaths:\n /devices:\n get:\n tags:\n - cnc\n summary: Get all device info\n operationId: getall\n responses:\n 200:\n description: Array of devices\n content:\n application/json:\n schema:\n $ref: '#/components/schemas/ListOfDevices'\n 404:\n description: No device found\n content: {}\n /devices/offline:\n post:\n tags:\n - cnc\n summary: Shut down all devices\n operationId: offlineall\n responses:\n 200:\n description: Message sent\n content: {}\n 500:\n description: Message sending unsuccessful\n content: {}\n /devices/online:\n post:\n tags:\n - cnc\n summary: Bring all devices online\n operationId: onlineall\n responses:\n 200:\n description: Message sent\n content: {}\n 500:\n description: Message sending unsuccessful\n content: {}\n /devices/{deviceID}:\n get:\n tags:\n - cnc\n summary: Get all device info\n operationId: getdevice\n parameters:\n - name: deviceID\n in: path\n description: ID of device to query\n required: true\n schema:\n type: string\n format: uuid\n responses:\n 200:\n description: Information about a particular device\n content:\n application/json:\n schema:\n $ref: '#/components/schemas/Device'\n 404:\n description: Device not found\n content: {}\n /devices/{deviceID}/offline:\n post:\n tags:\n - cnc\n summary: Shut down device\n operationId: offlinedevice\n parameters:\n - name: deviceID\n in: path\n description: ID of device to shut down\n required: true\n schema:\n type: string\n format: uuid\n responses:\n 200:\n description: Message sent\n content: {}\n 500:\n description: Message sending unsuccessful\n content: {}\n /devices/{deviceID}/online:\n post:\n tags:\n - cnc\n summary: Bring device online\n operationId: onlinedevice\n parameters:\n - name: deviceID\n in: path\n description: ID of device to bring online\n required: true\n schema:\n type: string\n format: uuid\n responses:\n 200:\n description: Message sent\n content: {}\n 500:\n description: Message sending unsuccessful\n content: {}\n /devices/{deviceID}/{sensorID}:\n get:\n tags:\n - cnc\n summary: Get info about a particular device's sensor\n operationId: getsensor\n parameters:\n - name: deviceID\n in: path\n description: ID of device to query\n required: true\n schema:\n type: string\n format: uuid\n - name: sensorID\n in: path\n description: ID of sensor to query\n required: true\n schema:\n type: string\n format: uuid\n responses:\n 200:\n description: Information about a sensor\n content:\n application/json:\n schema:\n $ref: '#/components/schemas/Sensor'\n 404:\n description: Device or sensor not found\n content: {}\n /devices/{deviceID}/{sensorID}/offline:\n post:\n tags:\n - cnc\n summary: Shut down sensor\n operationId: offlinesensor\n parameters:\n - name: deviceID\n in: path\n description: ID of device to query\n required: true\n schema:\n type: string\n format: uuid\n - name: sensorID\n in: path\n description: ID of sensor to query\n required: true\n schema:\n type: string\n format: uuid\n responses:\n 200:\n description: Message sent\n content: {}\n 500:\n description: Message sending unsuccessful\n content: {}\n /devices/{deviceID}/{sensorID}/online:\n post:\n tags:\n - cnc\n summary: Bring sensor online\n operationId: onlinesensor\n parameters:\n - name: deviceID\n in: path\n description: ID of device to query\n required: true\n schema:\n type: string\n format: uuid\n - name: sensorID\n in: path\n description: ID of sensor to query\n required: true\n schema:\n type: string\n format: uuid\n responses:\n 200:\n description: Message sent\n content: {}\n 500:\n description: Message sending unsuccessful\n content: {}\ncomponents:\n schemas:\n ListOfDevices:\n type: array\n items:\n $ref: '#/components/schemas/Device'\n Device:\n required:\n - id\n - sensors\n - status\n - url\n - coordinates\n type: object\n properties:\n id:\n type: string\n format: uuid\n status:\n type: string\n enum:\n - online\n - error\n - offline\n url:\n type: string\n format: url\n coordinates:\n required:\n - latitude\n - longitude\n type: object\n properties:\n latitude:\n type: number\n format: double\n longitude:\n type: number\n format: double\n sensors:\n $ref: '#/components/schemas/ArrayofSensors'\n ArrayofSensors:\n type: array\n items:\n $ref: '#/components/schemas/Sensor'\n Sensor:\n required:\n - id\n - status\n type: object\n properties:\n id:\n type: string\n format: uuid\n status:\n type: string\n enum:\n - online\n - unknown\n - offline", + "url": "https://git.kmlabz.com/birbnetes/swagger-docs/raw/branch/master/command-and-control.yml", + "output": null, + "newLineBehavior": "Auto" + } + }, + "codeGenerators": { + "openApiToTypeScriptClient": { + "className": "DeviceService", + "moduleName": "", + "namespace": "", + "typeScriptVersion": 2.7, + "template": "Fetch", + "promiseType": "Promise", + "httpClass": "HttpClient", + "withCredentials": false, + "useSingletonProvider": false, + "injectionTokenType": "OpaqueToken", + "rxJsVersion": 6.0, + "dateTimeType": "Date", + "nullValue": "Undefined", + "generateClientClasses": true, + "generateClientInterfaces": false, + "generateOptionalParameters": false, + "exportTypes": true, + "wrapDtoExceptions": false, + "exceptionClass": "ApiException", + "clientBaseClass": null, + "wrapResponses": false, + "wrapResponseMethods": [], + "generateResponseClasses": true, + "responseClass": "SwaggerResponse", + "protectedMethods": [], + "configurationClass": null, + "useTransformOptionsMethod": false, + "useTransformResultMethod": false, + "generateDtoTypes": true, + "operationGenerationMode": "MultipleClientsFromOperationId", + "markOptionalProperties": true, + "generateCloneMethod": false, + "typeStyle": "Class", + "enumStyle": "Enum", + "useLeafType": false, + "classTypes": [], + "extendedClasses": [], + "extensionCode": null, + "generateDefaultValues": true, + "excludedTypeNames": [], + "excludedParameterNames": [], + "handleReferences": false, + "generateConstructorInterface": true, + "convertConstructorInterfaceData": false, + "importRequiredTypes": true, + "useGetBaseUrlMethod": false, + "baseUrlTokenName": "API_BASE_URL", + "queryNullValue": "", + "inlineNamedDictionaries": false, + "inlineNamedAny": false, + "templateDirectory": null, + "typeNameGeneratorType": null, + "propertyNameGeneratorType": null, + "enumNameGeneratorType": null, + "serviceHost": null, + "serviceSchemes": null, + "output": null, + "newLineBehavior": "Auto" + }, + "openApiToCSharpClient": { + "clientBaseClass": null, + "configurationClass": null, + "generateClientClasses": true, + "generateClientInterfaces": true, + "clientBaseInterface": null, + "injectHttpClient": true, + "disposeHttpClient": true, + "protectedMethods": [], + "generateExceptionClasses": true, + "exceptionClass": "ApiException", + "wrapDtoExceptions": true, + "useHttpClientCreationMethod": false, + "httpClientType": "System.Net.Http.HttpClient", + "useHttpRequestMessageCreationMethod": false, + "useBaseUrl": true, + "generateBaseUrlProperty": true, + "generateSyncMethods": false, + "exposeJsonSerializerSettings": false, + "clientClassAccessModifier": "public", + "typeAccessModifier": "public", + "generateContractsOutput": false, + "contractsNamespace": null, + "contractsOutputFilePath": null, + "parameterDateTimeFormat": "s", + "parameterDateFormat": "yyyy-MM-dd", + "generateUpdateJsonSerializerSettingsMethod": true, + "useRequestAndResponseSerializationSettings": false, + "serializeTypeInformation": false, + "queryNullValue": "", + "className": "LiveDeviceService", + "operationGenerationMode": "MultipleClientsFromOperationId", + "additionalNamespaceUsages": [], + "additionalContractNamespaceUsages": [], + "generateOptionalParameters": false, + "generateJsonMethods": false, + "enforceFlagEnums": false, + "parameterArrayType": "System.Collections.Generic.IEnumerable", + "parameterDictionaryType": "System.Collections.Generic.IDictionary", + "responseArrayType": "System.Collections.Generic.ICollection", + "responseDictionaryType": "System.Collections.Generic.IDictionary", + "wrapResponses": false, + "wrapResponseMethods": [], + "generateResponseClasses": true, + "responseClass": "SwaggerResponse", + "namespace": "Birdmap.BLL.Services", + "requiredPropertiesMustBeDefined": true, + "dateType": "System.DateTimeOffset", + "jsonConverters": null, + "anyType": "object", + "dateTimeType": "System.DateTimeOffset", + "timeType": "System.TimeSpan", + "timeSpanType": "System.TimeSpan", + "arrayType": "System.Collections.Generic.ICollection", + "arrayInstanceType": "System.Collections.ObjectModel.Collection", + "dictionaryType": "System.Collections.Generic.IDictionary", + "dictionaryInstanceType": "System.Collections.Generic.Dictionary", + "arrayBaseType": "System.Collections.ObjectModel.Collection", + "dictionaryBaseType": "System.Collections.Generic.Dictionary", + "classStyle": "Poco", + "generateDefaultValues": true, + "generateDataAnnotations": true, + "excludedTypeNames": [], + "excludedParameterNames": [], + "handleReferences": false, + "generateImmutableArrayProperties": false, + "generateImmutableDictionaryProperties": false, + "jsonSerializerSettingsTransformationMethod": null, + "inlineNamedArrays": false, + "inlineNamedDictionaries": false, + "inlineNamedTuples": true, + "inlineNamedAny": false, + "generateDtoTypes": true, + "generateOptionalPropertiesAsNullable": false, + "generateNullableReferenceTypes": false, + "templateDirectory": null, + "typeNameGeneratorType": null, + "propertyNameGeneratorType": null, + "enumNameGeneratorType": null, + "serviceHost": null, + "serviceSchemes": null, + "output": null, + "newLineBehavior": "Auto" + }, + "openApiToCSharpController": { + "controllerBaseClass": null, + "controllerStyle": "Partial", + "controllerTarget": "AspNetCore", + "useCancellationToken": false, + "useActionResultType": true, + "generateModelValidationAttributes": true, + "routeNamingStrategy": "None", + "basePath": null, + "className": "{controller}", + "operationGenerationMode": "MultipleClientsFromOperationId", + "additionalNamespaceUsages": [], + "additionalContractNamespaceUsages": [], + "generateOptionalParameters": false, + "generateJsonMethods": false, + "enforceFlagEnums": false, + "parameterArrayType": "System.Collections.Generic.IEnumerable", + "parameterDictionaryType": "System.Collections.Generic.IDictionary", + "responseArrayType": "System.Collections.Generic.ICollection", + "responseDictionaryType": "System.Collections.Generic.IDictionary", + "wrapResponses": false, + "wrapResponseMethods": [], + "generateResponseClasses": true, + "responseClass": "SwaggerResponse", + "namespace": "Birdmap.API.Controllers", + "requiredPropertiesMustBeDefined": true, + "dateType": "System.DateTimeOffset", + "jsonConverters": null, + "anyType": "object", + "dateTimeType": "System.DateTimeOffset", + "timeType": "System.TimeSpan", + "timeSpanType": "System.TimeSpan", + "arrayType": "System.Collections.Generic.List", + "arrayInstanceType": "System.Collections.Generic.List", + "dictionaryType": "System.Collections.Generic.IDictionary", + "dictionaryInstanceType": "System.Collections.Generic.Dictionary", + "arrayBaseType": "System.Collections.ObjectModel.Collection", + "dictionaryBaseType": "System.Collections.Generic.Dictionary", + "classStyle": "Poco", + "generateDefaultValues": true, + "generateDataAnnotations": true, + "excludedTypeNames": [], + "excludedParameterNames": [], + "handleReferences": false, + "generateImmutableArrayProperties": false, + "generateImmutableDictionaryProperties": false, + "jsonSerializerSettingsTransformationMethod": null, + "inlineNamedArrays": false, + "inlineNamedDictionaries": false, + "inlineNamedTuples": true, + "inlineNamedAny": false, + "generateDtoTypes": true, + "generateOptionalPropertiesAsNullable": false, + "generateNullableReferenceTypes": false, + "templateDirectory": null, + "typeNameGeneratorType": null, + "propertyNameGeneratorType": null, + "enumNameGeneratorType": null, + "serviceHost": null, + "serviceSchemes": null, + "output": null, + "newLineBehavior": "Auto" + } + } +} \ No newline at end of file diff --git a/c-n-c.yml b/c-n-c.yml new file mode 100644 index 0000000..75048aa --- /dev/null +++ b/c-n-c.yml @@ -0,0 +1,272 @@ +openapi: 3.0.3 +info: + title: Command and Control Service + description: This service s responsible for controlling and handling information + about IoT devices in the Birbnetes system. + contact: + email: tormakristof@tormakristof.eu + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + version: 1.0.0 +servers: +- url: https://birb.k8s.kmlabz.com +tags: +- name: cnc + description: Command and Control Service interaction +paths: + /devices: + get: + tags: + - cnc + summary: Get all device info + operationId: getall + responses: + 200: + description: Array of devices + content: + application/json: + schema: + $ref: '#/components/schemas/ListOfDevices' + 404: + description: No device found + content: {} + /devices/offline: + post: + tags: + - cnc + summary: Shut down all devices + operationId: offlineall + responses: + 200: + description: Message sent + content: {} + 500: + description: Message sending unsuccessful + content: {} + /devices/online: + post: + tags: + - cnc + summary: Bring all devices online + operationId: onlineall + responses: + 200: + description: Message sent + content: {} + 500: + description: Message sending unsuccessful + content: {} + /devices/{deviceID}: + get: + tags: + - cnc + summary: Get all device info + operationId: getdevice + parameters: + - name: deviceID + in: path + description: ID of device to query + required: true + schema: + type: string + format: uuid + responses: + 200: + description: Information about a particular device + content: + application/json: + schema: + $ref: '#/components/schemas/Device' + 404: + description: Device not found + content: {} + /devices/{deviceID}/offline: + post: + tags: + - cnc + summary: Shut down device + operationId: offlinedevice + parameters: + - name: deviceID + in: path + description: ID of device to shut down + required: true + schema: + type: string + format: uuid + responses: + 200: + description: Message sent + content: {} + 500: + description: Message sending unsuccessful + content: {} + /devices/{deviceID}/online: + post: + tags: + - cnc + summary: Bring device online + operationId: onlinedevice + parameters: + - name: deviceID + in: path + description: ID of device to bring online + required: true + schema: + type: string + format: uuid + responses: + 200: + description: Message sent + content: {} + 500: + description: Message sending unsuccessful + content: {} + /devices/{deviceID}/{sensorID}: + get: + tags: + - cnc + summary: Get info about a particular device's sensor + operationId: getsensor + parameters: + - name: deviceID + in: path + description: ID of device to query + required: true + schema: + type: string + format: uuid + - name: sensorID + in: path + description: ID of sensor to query + required: true + schema: + type: string + format: uuid + responses: + 200: + description: Information about a sensor + content: + application/json: + schema: + $ref: '#/components/schemas/Sensor' + 404: + description: Device or sensor not found + content: {} + /devices/{deviceID}/{sensorID}/offline: + post: + tags: + - cnc + summary: Shut down sensor + operationId: offlinesensor + parameters: + - name: deviceID + in: path + description: ID of device to query + required: true + schema: + type: string + format: uuid + - name: sensorID + in: path + description: ID of sensor to query + required: true + schema: + type: string + format: uuid + responses: + 200: + description: Message sent + content: {} + 500: + description: Message sending unsuccessful + content: {} + /devices/{deviceID}/{sensorID}/online: + post: + tags: + - cnc + summary: Bring sensor online + operationId: onlinesensor + parameters: + - name: deviceID + in: path + description: ID of device to query + required: true + schema: + type: string + format: uuid + - name: sensorID + in: path + description: ID of sensor to query + required: true + schema: + type: string + format: uuid + responses: + 200: + description: Message sent + content: {} + 500: + description: Message sending unsuccessful + content: {} +components: + schemas: + ListOfDevices: + type: array + items: + $ref: '#/components/schemas/Device' + Device: + required: + - id + - sensors + - status + - url + - coordinates + type: object + properties: + id: + type: string + format: uuid + status: + type: string + enum: + - online + - error + - offline + url: + type: string + format: url + coordinates: + required: + - latitude + - longitude + type: object + properties: + latitude: + type: number + format: double + longitude: + type: number + format: double + sensors: + $ref: '#/components/schemas/ArrayofSensors' + ArrayofSensors: + type: array + items: + $ref: '#/components/schemas/Sensor' + Sensor: + required: + - id + - status + type: object + properties: + id: + type: string + format: uuid + status: + type: string + enum: + - online + - unknown + - offline \ No newline at end of file diff --git a/docs/Dashboard.jpg b/docs/Dashboard.jpg new file mode 100644 index 0000000000000000000000000000000000000000..529fd7a3114751ace818695558b8963185151b70 GIT binary patch literal 50055 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≫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 z z>9=-KOXPmz(ax%%xG%9?KFZx1>>WiBxktR9fw4NmmP@=<{+#>qYZM0l<0;oAx7g#Jt@3eMK5j_;gbl%Kd}M zseRGUOaBJhm7-|1839ayu5tdkBbG0TtsnIRgr+`e z7C9{4&3b$f`(DLp&ygl_DZ?tE8s~a=3R+E(-3JThN&s_!KxMW=*Xr*LFUNezuDI8T zXoL2IXn_mthX+#E+Ck?T*3;107syP`do1KN9z+8xYOTYWaRx;+-Aw~DnjyHi+*JRF zZ8Pd#a2=5X*C8Ls1J4hHXo2B)KNSI;V1{kYl+w%iok;&1<#7rpMgzKzor0)JeO&L_ zF50pvkHR^ec+1j8k;Pbk{P+WY1w(#E4nq!*vl+WIL~!_