aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sdnr/wt/odlux/apps/app-feature/pom.xml5
-rwxr-xr-xsdnr/wt/odlux/apps/app-installer/pom.xml5
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx5
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts1
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/.babelrc17
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/package.json47
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/pom.xml160
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/actions/commonActions.ts80
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/actions/mapActions.ts67
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/components/ConnectionErrorPoup.tsx40
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/components/heightChart.tsx126
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/components/map.tsx329
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/components/mapContextMenu.tsx86
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/components/mapInfo.tsx171
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/config.ts48
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/handlers/mapHandler.ts82
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/handlers/rootHandler.ts48
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/hooks/d3.ts37
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/index.html31
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/model/GPSProfileResult.ts19
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/model/Height.tsx22
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/model/LatLon.ts22
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/pluginLineOfSight.tsx138
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/services/heightService.ts62
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/styles/index.css13
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/styles/mapbox-gl.css1
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/utils/map.ts103
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/utils/math.ts30
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src/views/main.tsx30
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java68
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml9
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src2/test/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/test/TestBundleRes.java46
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/src2/test/resources/test.js5
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/tsconfig.json37
-rw-r--r--sdnr/wt/odlux/apps/lineOfSightApp/webpack.config.js211
-rw-r--r--sdnr/wt/odlux/apps/linkCalculationApp/src/actions/commonLinkCalculationActions.ts55
-rw-r--r--sdnr/wt/odlux/apps/linkCalculationApp/src/handlers/linkCalculationAppRootHandler.ts60
-rw-r--r--sdnr/wt/odlux/apps/linkCalculationApp/src/index.html3
-rw-r--r--sdnr/wt/odlux/apps/linkCalculationApp/src/pluginLinkCalculation.tsx99
-rw-r--r--sdnr/wt/odlux/apps/linkCalculationApp/src/views/linkCalculationComponent.tsx115
-rw-r--r--sdnr/wt/odlux/apps/linkCalculationApp/webpack.config.js14
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/components/ltpSelection.tsx2
-rw-r--r--sdnr/wt/odlux/framework/package.json2
-rw-r--r--sdnr/wt/odlux/framework/pom.xml2
-rw-r--r--sdnr/wt/odlux/framework/src/views/about.tsx6
-rw-r--r--sdnr/wt/odlux/installer/pom.xml11
-rw-r--r--sdnr/wt/odlux/odlux.properties7
-rw-r--r--sdnr/wt/odlux/package.json2
-rw-r--r--sdnr/wt/odlux/pom.xml1
-rw-r--r--sdnr/wt/odlux/yarn.lock488
50 files changed, 2905 insertions, 163 deletions
diff --git a/sdnr/wt/odlux/apps/app-feature/pom.xml b/sdnr/wt/odlux/apps/app-feature/pom.xml
index 738ac6964..17c0dab6e 100644
--- a/sdnr/wt/odlux/apps/app-feature/pom.xml
+++ b/sdnr/wt/odlux/apps/app-feature/pom.xml
@@ -106,6 +106,11 @@
<artifactId>sdnr-wt-odlux-app-linkCalculationApp</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sdnr-wt-odlux-app-lineOfSightApp</artifactId>
+ <version>${project.version}</version>
+ </dependency>
diff --git a/sdnr/wt/odlux/apps/app-installer/pom.xml b/sdnr/wt/odlux/apps/app-installer/pom.xml
index 1ac88593f..721d56488 100755
--- a/sdnr/wt/odlux/apps/app-installer/pom.xml
+++ b/sdnr/wt/odlux/apps/app-installer/pom.xml
@@ -132,6 +132,11 @@
<artifactId>sdnr-wt-odlux-app-linkCalculationApp</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sdnr-wt-odlux-app-lineOfSightApp</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
diff --git a/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx b/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx
index 5d0757ab2..4a7a0d269 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx
+++ b/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx
@@ -194,11 +194,12 @@ export class NetworkElementsListComponent extends React.Component<NetworkElement
<NetworkElementTable stickyHeader tableId="network-element-table" customActionButtons={[refreshNetworkElementsAction, ...canAdd ? [addRequireNetworkElementAction] : []]} columns={[
{ property: "nodeId", title: "Node Name", type: ColumnType.text },
{ property: "isRequired", title: "Required", type: ColumnType.boolean },
- { property: "status", title: "Connection Status", type: ColumnType.text },
+ { property: "status", title: "Connection Status", type: ColumnType.text, width:'15%' },
{ property: "host", title: "Host", type: ColumnType.text },
{ property: "port", title: "Port", type: ColumnType.numeric },
{ property: "coreModelCapability", title: "Core Model", type: ColumnType.text },
- { property: "deviceType", title: "Type", type: ColumnType.text },
+ { property: "deviceType", title: "Device Type", type: ColumnType.text },
+ { property: "deviceFunction", title: "Device Function", type: ColumnType.text, width: '15%' }
]} idProperty="id" {...this.props.networkElementsActions} {...this.props.networkElementsProperties} asynchronus createContextMenu={rowData => {
return this.getContextMenu(rowData);
diff --git a/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts b/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts
index 89070ab39..bc15afb31 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts
+++ b/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts
@@ -30,6 +30,7 @@ export type NetworkElementConnection = {
status?: "Connected" | "mounted" | "unmounted" | "Connecting" | "Disconnected" | "idle";
coreModelCapability?: string;
deviceType?: string;
+ deviceFunction?: string;
nodeDetails?: {
availableCapabilites: {
capabilityOrigin: string;
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/.babelrc b/sdnr/wt/odlux/apps/lineOfSightApp/.babelrc
new file mode 100644
index 000000000..3d8cd1260
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/.babelrc
@@ -0,0 +1,17 @@
+{
+ "presets": [
+ ["@babel/preset-react"],
+ ["@babel/preset-env", {
+ "targets": {
+ "chrome": "66"
+ },
+ "spec": true,
+ "loose": false,
+ "modules": false,
+ "debug": false,
+ "useBuiltIns": "usage",
+ "forceAllTransforms": true
+ }]
+ ],
+ "plugins": []
+}
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/package.json b/sdnr/wt/odlux/apps/lineOfSightApp/package.json
new file mode 100644
index 000000000..dbba7ecfb
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/package.json
@@ -0,0 +1,47 @@
+{
+ "name": "@odlux/line-of-sight-app",
+ "version": "0.1.0",
+ "description": "A react based modular UI to display event log from a database.",
+ "main": "index.js",
+ "scripts": {
+ "start": "webpack-dev-server --env debug",
+ "build": "webpack --env release --config webpack.config.js",
+ "build:dev": "webpack --env debug --config webpack.config.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://git.mfico.de/highstreet-technologies/odlux.git"
+ },
+ "keywords": [
+ "reactjs",
+ "redux",
+ "ui",
+ "framework"
+ ],
+ "author": "Aijana Schumann",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@odlux/framework": "*",
+ "@types/d3": "^6.7.0",
+ "@types/mapbox-gl": "^1.10.2",
+ "@types/node": "^12.0.0",
+ "d3": "^7.0.0",
+ "d3-polygon": "^3.0.1",
+ "mapbox-gl": "^1.11.0",
+ "object.values": "^1.1.1"
+ },
+ "peerDependencies": {
+ "@material-ui/core": "4.11.4",
+ "@material-ui/icons": "4.11.2",
+ "@types/classnames": "2.2.6",
+ "@types/flux": "3.1.8",
+ "@types/jquery": "3.3.10",
+ "@types/react": "17.0.3",
+ "@types/react-dom": "17.0.2",
+ "@types/react-router-dom": "5.1.7",
+ "jquery": "3.3.1",
+ "react": "17.0.1",
+ "react-dom": "17.0.1",
+ "react-router-dom": "5.2.0"
+ }
+}
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/pom.xml b/sdnr/wt/odlux/apps/lineOfSightApp/pom.xml
new file mode 100644
index 000000000..29184a78b
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/pom.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ ============LICENSE_START=======================================================
+ ~ ONAP : ccsdk features
+ ~ ================================================================================
+ ~ Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ ~ ================================================================================
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~ ============LICENSE_END=======================================================
+ ~
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onap.ccsdk.parent</groupId>
+ <artifactId>binding-parent</artifactId>
+ <version>2.2.0-SNAPSHOT</version>
+ <relativePath/>
+ </parent>
+
+ <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+ <artifactId>sdnr-wt-odlux-app-lineOfSightApp</artifactId>
+ <version>1.2.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <name>ccsdk-features :: ${project.artifactId}</name>
+ <licenses>
+ <license>
+ <name>Apache License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0</url>
+ </license>
+ </licenses>
+
+ <properties>
+ <maven.javadoc.skip>true</maven.javadoc.skip>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sdnr-wt-odlux-core-model</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sdnr-wt-odlux-core-provider</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <sourceDirectory>src2/main/java</sourceDirectory>
+ <resources>
+ <resource>
+ <directory>dist</directory>
+ <targetPath>odlux</targetPath>
+ </resource>
+ <resource>
+ <directory>src2/main/resources</directory>
+ </resource>
+ <resource>
+ <directory>src2/test/resources</directory>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <artifactId>maven-clean-plugin</artifactId>
+ <configuration>
+ <filesets>
+ <fileset>
+ <directory>dist</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ <fileset>
+ <directory>node</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ <fileset>
+ <directory>node_modules</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ <fileset>
+ <directory>../node_modules</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ <!-- eclipse bug build bin folder in basedir -->
+ <fileset>
+ <directory>bin</directory>
+ <followSymlinks>false</followSymlinks>
+ </fileset>
+ </filesets>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>add-test-source</id>
+ <phase>generate-test-sources</phase>
+ <goals>
+ <goal>add-test-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>src2/test/java</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>de.jacks-it-lab</groupId>
+ <artifactId>frontend-maven-plugin</artifactId>
+ <version>1.7.2</version>
+ <executions>
+ <execution>
+ <id>install node and yarn</id>
+ <goals>
+ <goal>install-node-and-yarn</goal>
+ </goals>
+ <!-- optional: default phase is "generate-resources" -->
+ <phase>initialize</phase>
+ <configuration>
+ <nodeVersion>v12.13.0</nodeVersion>
+ <yarnVersion>v1.22.10</yarnVersion>
+ </configuration>
+ </execution>
+ <execution>
+ <id>yarn build</id>
+ <goals>
+ <goal>yarn</goal>
+ </goals>
+ <configuration>
+ <arguments>run build</arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/actions/commonActions.ts b/sdnr/wt/odlux/apps/lineOfSightApp/src/actions/commonActions.ts
new file mode 100644
index 000000000..3cc8ea4a7
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/actions/commonActions.ts
@@ -0,0 +1,80 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+ import { Height } from "model/Height";
+import { isNumber } from "../utils/math";
+import { Action } from "../../../../framework/src/flux/action";
+ import { Dispatch } from "../../../../framework/src/flux/store";
+ import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore";
+
+ import { LatLon } from "../model/LatLon";
+
+
+ export class SetPassedInValuesAction extends Action{
+ constructor(public start: LatLon, public end: LatLon, public center: LatLon, public heightA : Height |null, public heightB: Height |null){
+ super();
+ }
+ }
+
+ export class SetReachableAction extends Action{
+ constructor(public reachable: boolean | null){
+ super();
+ }
+ }
+
+ export const SetPassedInValues = (values: (string|null)[]) => (dispatcher: Dispatch) =>{
+
+ const start: LatLon = {latitude: Number(values[0]), longitude: Number(values[1])}
+ const end: LatLon = {latitude: Number(values[2]), longitude: Number(values[3])};
+ const midpoint = calculateMidPoint(start.latitude, start.longitude, end.latitude, end.longitude);
+ const center: LatLon = {latitude: midpoint[1], longitude: midpoint[0]};
+ const heightA: Height | null = isNumber(values[4]) && isNumber(values[5]) ? {amsl:+values[4]!, antennaHeight: +values[5]!} : null;
+ const heightB: Height | null = isNumber(values[6]) && isNumber(values[7]) ? {amsl:+values[6]!, antennaHeight: +values[7]!} : null;
+
+
+ dispatcher(new SetPassedInValuesAction(start, end, center, heightA, heightB));
+ }
+
+ //taken from https://www.movable-type.co.uk/scripts/latlong.html
+const calculateMidPoint = (lat1: number, lon1: number, lat2: number, lon2: number) =>{
+
+ const dLon = degrees_to_radians(lon2 - lon1);
+
+ //convert to radians
+ lat1 = degrees_to_radians(lat1);
+ lat2 = degrees_to_radians(lat2);
+ lon1 = degrees_to_radians(lon1);
+
+ const Bx = Math.cos(lat2) * Math.cos(dLon);
+ const By = Math.cos(lat2) * Math.sin(dLon);
+ const lat3 = Math.atan2(Math.sin(lat1) + Math.sin(lat2), Math.sqrt((Math.cos(lat1) + Bx) * (Math.cos(lat1) + Bx) + By * By));
+ const lon3 = lon1 + Math.atan2(By, Math.cos(lat1) + Bx);
+
+ return [radians_to_degrees(lon3), radians_to_degrees(lat3)];
+}
+
+const degrees_to_radians = (degrees: number) =>
+{
+return degrees * (Math.PI/180);
+}
+
+const radians_to_degrees = (radians:number) =>{
+
+ var pi = Math.PI;
+ return radians * (180/pi);
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/actions/mapActions.ts b/sdnr/wt/odlux/apps/lineOfSightApp/src/actions/mapActions.ts
new file mode 100644
index 000000000..37ef5ee25
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/actions/mapActions.ts
@@ -0,0 +1,67 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+import { LatLon } from "../model/LatLon";
+import { Action } from "../../../../framework/src/flux/action";
+import { Height } from "model/Height";
+
+export class SetChartAction extends Action{
+ constructor(public startPoint: LatLon, public endPoint: LatLon, public heightA: Height, public heightB: Height){
+ super();
+ }
+}
+
+export class SetStartPointAction extends Action{
+ constructor(public startPoint: LatLon|null){
+ super();
+ }
+}
+
+export class SetEndpointAction extends Action{
+ constructor(public endPoint: LatLon|null){
+ super();
+ }
+}
+
+export class SetHeightA extends Action{
+ constructor(public height: Height){
+ super();
+ }
+}
+
+export class SetHeightB extends Action{
+ constructor(public height: Height){
+ super();
+ }
+}
+
+export class ClearSavedChartAction extends Action{
+ constructor(){
+ super();
+ }
+}
+
+export class SetMapCenterAction extends Action{
+ /**
+ *
+ */
+ constructor(public point: LatLon, public zoom: number) {
+ super();
+
+ }
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/components/ConnectionErrorPoup.tsx b/sdnr/wt/odlux/apps/lineOfSightApp/src/components/ConnectionErrorPoup.tsx
new file mode 100644
index 000000000..7d9339fc0
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/components/ConnectionErrorPoup.tsx
@@ -0,0 +1,40 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+import { faExclamationTriangle } from "@fortawesome/free-solid-svg-icons"
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
+import { Paper, Typography } from "@material-ui/core"
+import * as React from "react"
+
+type props = { reachable: boolean|null};
+
+
+const ConnectionErrorPoup: React.FunctionComponent<props> = (props) => {
+
+ return (props.reachable === false ?
+ <Paper style={{padding:5, position: 'absolute', top: 160, width: 230, left:"40%", zIndex:1}}>
+ <div style={{display: 'flex', flexDirection: 'column'}}>
+ <div style={{'alignSelf': 'center', marginBottom:5}}> <Typography> <FontAwesomeIcon icon={faExclamationTriangle} /> Connection Error</Typography></div>
+ <Typography>Service unavailable</Typography>
+ </div>
+ </Paper> : null
+)
+
+}
+
+export default ConnectionErrorPoup; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/components/heightChart.tsx b/sdnr/wt/odlux/apps/lineOfSightApp/src/components/heightChart.tsx
new file mode 100644
index 000000000..3030fe7dd
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/components/heightChart.tsx
@@ -0,0 +1,126 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+import * as React from 'react';
+
+import type { FC } from 'react';
+import * as d3 from 'd3';
+
+import { useD3 } from "../hooks/d3";
+import { GPSProfileResult } from "../model/GPSProfileResult";
+import { max } from '../utils/math';
+
+type HeightMapProps = {
+ data: GPSProfileResult[];
+ dataMin: GPSProfileResult;
+ dataMax: GPSProfileResult;
+ width: number;
+ height: number;
+ heightPosA: number;
+ heightPosB: number;
+}
+
+const HeightChart: FC<HeightMapProps> = (props) => {
+ const { data, dataMin, dataMax, heightPosA, heightPosB } = props;
+ let ref: React.RefObject<SVGSVGElement>
+
+ const drawSvg = () => {
+ ref = useD3(
+ (svg) => {
+ const margin = 100;
+ const width = Number(svg.attr("width")) - margin;
+ const height = Number(svg.attr("height")) - margin;
+
+ // Add X axis
+ const x = d3.scaleBand()
+ .range([0, width])
+ .domain(data.map(d => (`${d.gps.latitude},${d.gps.latitude}`)))
+ .padding(0.2);
+
+ const maxHeight = max([dataMax.height, heightPosA, heightPosB], d => d)
+
+ // Add Y axis
+ const y = d3.scaleLinear()
+ .domain([dataMin.height, maxHeight])
+ .range([height, 0]);
+
+ svg.append("g")
+ .attr('transform', `translate(${margin / 2}, ${margin / 2})`)
+ .call(d3.axisLeft(y));
+
+ // Bars
+ svg.selectAll("myBar")
+ .data(data)
+ .join("rect")
+ .attr('transform', `translate(${margin / 2}, ${margin / 2})`)
+ .attr("x", d => x(`${d.gps.latitude},${d.gps.latitude}`) || '')
+ .attr("y", d => y(d.height))
+ .attr("width", x.bandwidth())
+ .attr("fill", "#69b3a2b0")
+ .attr("height", d => height - y(d.height)) // always equal to 0
+
+ const firstX = `${data[0].gps.latitude},${data[0].gps.latitude}`
+ const lastX = `${data[data.length - 1].gps.latitude},${data[data.length - 1].gps.latitude}`;
+
+ //add line
+ const x1 = x(firstX)!;
+ const x2 = x(lastX)!;
+
+ svg.append("line")
+ .attr('transform', `translate(${margin / 2}, ${margin / 2})`)
+ .attr("x1", x1)
+ .attr("y1", y(props.heightPosA))
+ .attr("x2", x2)
+ .attr("y2", y(props.heightPosB))
+
+ .style("stroke", "#88A")
+ .attr("stroke-width", "3px")
+
+ //append circle on start and end
+
+ svg.append("circle")
+ .attr('transform', `translate(${margin / 2}, ${margin / 2})`)
+ .attr('cx', x1)
+ .attr('cy', y(props.heightPosA))
+ .attr('r', 10)
+ .attr('stroke', '#223b53')
+ .attr('fill', '#225ba3');
+
+ svg.append("circle")
+ .attr('transform', `translate(${margin / 2}, ${margin / 2})`)
+ .attr('cx', x2)
+ .attr('cy', y(props.heightPosB))
+ .attr('r', 10)
+ .attr('stroke', '#223b53')
+ .attr('fill', '#225ba3');
+ },
+ [data]
+ );
+ }
+
+ drawSvg();
+
+
+
+ return (
+ <svg ref={ref!} width={props.width} height={props.height} />
+
+ );
+}
+
+export { HeightChart };
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/components/map.tsx b/sdnr/wt/odlux/apps/lineOfSightApp/src/components/map.tsx
new file mode 100644
index 000000000..6f29d5993
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/components/map.tsx
@@ -0,0 +1,329 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+import * as React from 'react'
+import * as mapboxgl from 'mapbox-gl';
+import { render } from 'react-dom';
+import { RouteComponentProps, withRouter } from 'react-router-dom';
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+import connect, { Connect, IDispatcher } from '../../../../framework/src/flux/connect';
+import { OSM_STYLE, URL_BASEPATH } from '../config';
+import { GPSProfileResult } from '../model/GPSProfileResult';
+import MapContextMenu from './mapContextMenu';
+import { getGPSProfile } from '../services/heightService';
+import { max, min } from '../utils/math';
+import { HeightChart } from './heightChart';
+import { makeStyles } from '@material-ui/core';
+import { ClearSavedChartAction, SetChartAction, SetEndpointAction, SetHeightA, SetHeightB, SetMapCenterAction, SetStartPointAction } from '../actions/mapActions';
+import { LatLon } from '../model/LatLon';
+import MapInfo from './mapInfo';
+import { Height } from 'model/Height';
+import { PictureAsPdf } from '@material-ui/icons';
+import ConnectionErrorPoup from './ConnectionErrorPoup';
+import { addBaseLayer, addBaseSource, addPoint } from '../utils/map';
+import { SetReachableAction } from '../actions/commonActions';
+
+import 'mapbox-gl/dist/mapbox-gl.css';
+
+type mapProps = RouteComponentProps & Connect<typeof mapStateToProps, typeof mapDispatchToProps>;
+
+const mapStateToProps = (state: IApplicationStoreState) => ({
+ center: state.lineOfSight.map.center,
+ zoom: state.lineOfSight.map.zoom,
+ start: state.lineOfSight.map.start,
+ end: state.lineOfSight.map.end,
+ heightA: state.lineOfSight.map.heightA,
+ heightB: state.lineOfSight.map.heightB,
+ ready: state.lineOfSight.map.ready
+});
+
+const mapDispatchToProps = (dispatcher: IDispatcher) => ({
+ ClearChartAction: () => dispatcher.dispatch(new ClearSavedChartAction),
+ SetMapPosition: (point: LatLon, zoom: number) => dispatcher.dispatch(new SetMapCenterAction(point, zoom)),
+ SetHeightStart: (height: Height) => dispatcher.dispatch(new SetHeightA(height)),
+ SetHeightEnd: (height: Height) => dispatcher.dispatch(new SetHeightB(height)),
+ setStartPosition: (position: LatLon|null) => dispatcher.dispatch(new SetStartPointAction(position)),
+ setEndPosition: (position: LatLon|null) => dispatcher.dispatch(new SetEndpointAction(position)),
+ setReachable : (reachable: boolean |null) => dispatcher.dispatch(new SetReachableAction(reachable)),
+
+
+
+})
+
+
+let map: mapboxgl.Map;
+
+const styles = makeStyles({
+ chart: {
+ position: "absolute",
+ top: 0,
+ bottom: 0,
+ left: 0,
+ right: 0
+
+ }
+ });
+
+
+const Map: React.FC<mapProps> = (props) => {
+
+ //const [start, setStart] = React.useState<mapboxgl.LngLat| undefined>();
+ //const [end, setEnd] = React.useState<mapboxgl.LngLat| undefined>();
+ const [data, setData] = React.useState<GPSProfileResult[] | number>(Number.NaN);
+ const [dataMin, setDataMin] = React.useState<GPSProfileResult|undefined>();
+ const [dataMax, setDataMax] = React.useState<GPSProfileResult|undefined>();
+ const [isMapLoaded, setMapLoaded] = React.useState<boolean>(false);
+
+
+const mapRef = React.useRef<{ map: mapboxgl.Map | null }>({ map: null });
+const mapContainerRef = React.useRef<HTMLDivElement>(null);
+
+
+
+const classes = styles();
+
+const heightA = props.heightA !== null ? props.heightA.amsl + props.heightA.antennaHeight : 0;
+const heightB = props.heightB !== null ? props.heightB.amsl + props.heightB.antennaHeight : 0;
+
+const {start, end} = props;
+
+const handleResize = () =>{
+
+ if (map) {
+ // wait a moment until resizing actually happened
+ window.setTimeout(() => map.resize(), 500);
+ }
+
+}
+
+//on mount
+React.useEffect(()=>{
+
+ window.addEventListener("menu-resized", handleResize);
+
+
+ return () =>{
+ console.log("unmount")
+ window.removeEventListener("menu-resized", handleResize);
+
+ const center = mapRef.current.map?.getCenter();
+ const mapZoom = mapRef.current.map?.getZoom();
+ if(center){
+ props.SetMapPosition({latitude: center.lat, longitude:center.lng}, mapZoom!);
+ }
+
+ props.setReachable(null);
+ }
+
+},[]);
+
+
+ React.useEffect(()=>{
+
+ if(props.ready){
+ setupMap();
+ }
+
+ },[props.ready]);
+
+ React.useEffect(() => {
+ if (props.ready && isMapLoaded) {
+ drawChart();
+ updateLosUrl();
+ }
+
+ }, [start, end, isMapLoaded]);
+
+ const drawChart = () =>{
+ if(start && end){
+
+ addBaseSource(map, 'route');
+ addBaseLayer(map, 'route');
+
+ const json = `{
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "LineString",
+ "coordinates": [
+ [${start.longitude}, ${start.latitude}],
+ [${end.longitude}, ${end.latitude}]
+ ]}
+ }`;
+
+
+
+ (map.getSource("route") as mapboxgl.GeoJSONSource).setData(JSON.parse(json));
+
+
+ getGPSProfile({ latitude: start.latitude, longitude: start.longitude }, { latitude: end.latitude, longitude: end.longitude }).then(data => {
+ if (Array.isArray(data)) {
+ setDataMin(min(data, d => d.height));
+ setDataMax(max(data, d => d.height));
+ }
+ setData(data);
+ });
+ }
+ else if (start || end){
+
+ const point = start!==null ? start: end!;
+ addBaseSource(map, 'route');
+ addBaseLayer(map, 'route');
+ addPoint(map, point);
+
+ }
+ else {
+ //delete layers and source
+ //used instead of clearing source data because it has better performance
+ //(setting data to empty results in a noticable lag of line being cleared)
+ mapRef.current.map?.getLayer('line') && mapRef.current.map?.removeLayer('line') && mapRef.current.map?.removeLayer('points') && mapRef.current.map?.removeSource('route');
+
+ }
+ }
+
+ const updateLosUrl = () =>{
+
+ if(start && end){
+
+ const locationPart = `lat1=${start.latitude}&lon1=${start.longitude}&lat2=${end.latitude}&lon2=${end.longitude}`;
+
+ let heightPart = '';
+
+ if(props.heightA && props.heightB){
+ heightPart = `&amslA=${props.heightA.amsl}&antennaHeightA=${props.heightA.antennaHeight}&amslB=${props.heightB.amsl}&antennaHeightB=${props.heightB.antennaHeight}`;
+
+ }
+
+ props.history.replace(`/${URL_BASEPATH}/los?${locationPart}${heightPart}`)
+
+ }else if(!start && !end){
+ props.history.replace(`/${URL_BASEPATH}`);
+ }
+ }
+
+
+ const updateHeightA = (value:number, value2: number) =>{
+ props.SetHeightStart({amsl: value, antennaHeight: value2});
+ }
+
+ const updateHeightB = (value:number, value2: number) =>{
+ props.SetHeightEnd({amsl: value, antennaHeight: value2});
+ }
+
+ const OnEndPosition = (position: mapboxgl.LngLat) =>{
+ props.setEndPosition({latitude: position.lat, longitude: position.lng})
+ }
+
+ const OnStartPosition = (position: mapboxgl.LngLat) =>{
+ props.setStartPosition({latitude: position.lat, longitude: position.lng})
+ }
+
+
+ const setupMap = () => {
+
+ let lat = props.center.latitude
+ let lon = props.center.longitude;
+ let zoom = props.zoom;
+
+ map = new mapboxgl.Map({
+ container: mapContainerRef.current!,
+ style: OSM_STYLE as any,
+ center: [lon, lat],
+ zoom: zoom,
+ accessToken: ''
+ });
+
+ mapRef.current.map = map;
+
+ map.on('load', (ev) => {
+
+ map.setMaxZoom(18);
+ setMapLoaded(true);
+
+ //add source, layer
+
+ addBaseSource(map, 'route');
+ addBaseLayer(map, 'route');
+
+ });
+
+ let currentPopup: mapboxgl.Popup | null = null;
+ map.on('contextmenu', (e) => {
+
+ if (currentPopup)
+ currentPopup.remove();
+
+ //change height if start/end changes
+ //??? -> show value? / reset after chart display?
+
+ const popupNode = document.createElement("div");
+ render(
+ <MapContextMenu pos={e.lngLat}
+ onStart={(p) => { OnStartPosition(p); if (currentPopup) currentPopup.remove(); }}
+ onEnd={(p) => { OnEndPosition(p); if (currentPopup) currentPopup.remove(); }}
+ onHeightA={(p,p1)=> updateHeightA(p, p1)}
+ onHeightB={(p, p1)=> updateHeightB(p, p1)} />,
+ popupNode);
+
+ currentPopup = new mapboxgl.Popup()
+ .setLngLat(e.lngLat)
+ .setDOMContent(popupNode)
+ .addTo(map);
+ });
+
+ map.on('moveend', mapMoveEnd);
+
+ };
+
+ const mapMoveEnd = () =>{
+ const mapZoom = Number(map.getZoom().toFixed(2));
+ const lat = Number(map.getCenter().lat.toFixed(4));
+ const lon = Number(map.getCenter().lng.toFixed(4));
+
+ props.SetMapPosition({latitude: lat, longitude: lon}, mapZoom);
+
+ }
+
+
+
+ return <>
+ <div id="map" style={{ width: "100%", height:'100%', position: 'relative' }} ref={mapContainerRef} >
+ <MapInfo minHeight={dataMin} maxHeight={dataMax} />
+ <ConnectionErrorPoup reachable={props.ready} />
+
+ {typeof data === "object"
+ ? (
+ < div className={classes.chart} onClick={() => {
+ setData(Number.NaN);
+ setDataMax(undefined);
+ setDataMin(undefined);
+ props.ClearChartAction();
+ }}>
+ <HeightChart heightPosA={heightA} heightPosB={heightB} width={mapContainerRef.current?.clientWidth!} height={mapContainerRef.current?.clientHeight!} data={data} dataMin={dataMin!} dataMax={dataMax!} />
+ </div>
+ )
+ : null
+ }
+
+ </div>
+ </>
+}
+
+export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Map));
+
+
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/components/mapContextMenu.tsx b/sdnr/wt/odlux/apps/lineOfSightApp/src/components/mapContextMenu.tsx
new file mode 100644
index 000000000..0fc51cabf
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/components/mapContextMenu.tsx
@@ -0,0 +1,86 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+import { Button, InputAdornment, makeStyles, TextField, Tooltip } from "@material-ui/core";
+import * as React from "react";
+import { FC, useEffect, useState } from "react";
+import { getGPSHeight } from "../services/heightService";
+
+type MapContextMenuProps = {
+ pos: mapboxgl.LngLat;
+ onStart: (pos: mapboxgl.LngLat) => void;
+ onEnd: (pos: mapboxgl.LngLat) => void;
+ onHeightA: (height: number, antennaHeight: number) => void;
+ onHeightB: (height: number, antennaHeight: number) => void;
+
+ }
+
+ const styles = makeStyles({
+ flexContainer: {display: "flex", flexDirection:"row"},
+ textField:{width:60},
+ button:{marginRight:5, marginTop:5, flexGrow:2}
+ });
+
+ const MapContextMenu: FC<MapContextMenuProps> = (props) => {
+ const { pos, onStart, onEnd } = props;
+ const [height, setHeight] = useState<number | undefined>(undefined);
+ const [value1, setValue1] = useState<string>('');
+ const [value2, setValue2] = useState<string>('');
+
+ const classes = styles();
+
+ useEffect(() => {
+ getGPSHeight({ longitude: pos.lng, latitude: pos.lat }).then(setHeight);
+ }, [pos.lat, pos.lng]);
+
+ const handleChangeHeight = (e:React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>, id: "heightA"|"heightB") =>{
+
+ //sanitize non numbers
+ const onlyNums = e.target.value.replace(/[^0-9]/g, '');
+
+ if(id==="heightA"){
+ setValue1(onlyNums);
+ }else{
+ setValue2(onlyNums);
+ }
+ }
+
+ return (
+ <div>
+ <div>Height: {height} m</div>
+ <div>
+ <div className={classes.flexContainer}>
+ <Button className={classes.button} variant="contained" onClick={() => { onStart(pos); props.onHeightA(height!,+value1); }}>Start</Button>
+ <Tooltip title="Please add the antenna height in meters above sea level.">
+ <TextField className={classes.textField} value={value1} onChange={(e)=>handleChangeHeight(e,"heightA")} InputProps={{endAdornment: <InputAdornment position="start">m</InputAdornment>}}/>
+ </Tooltip>
+ </div>
+ <div className={classes.flexContainer}>
+ <Button className={classes.button} variant="contained" onClick={() => { onEnd(pos); props.onHeightB(height!,+value2);}}>End</Button>
+ <Tooltip title="Please add the antenna height in meters above sea level.">
+ <TextField className={classes.textField} value={value2} onChange={(e)=>handleChangeHeight(e,"heightB")} InputProps={{endAdornment: <InputAdornment position="start">m</InputAdornment>}}/>
+ </Tooltip>
+ </div>
+ </div>
+
+ </div>
+ );
+ };
+
+
+ export default MapContextMenu; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/components/mapInfo.tsx b/sdnr/wt/odlux/apps/lineOfSightApp/src/components/mapInfo.tsx
new file mode 100644
index 000000000..43a6e478a
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/components/mapInfo.tsx
@@ -0,0 +1,171 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+import { Accordion, AccordionDetails, AccordionSummary, makeStyles, Paper, Typography } from '@material-ui/core';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import { GPSProfileResult } from '../model/GPSProfileResult';
+import * as React from 'react';
+import { calculateDistanceInMeter } from '../utils/map';
+import connect, { Connect, IDispatcher } from '../../../../framework/src/flux/connect';
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+
+const mapStateToProps = (state: IApplicationStoreState) => ({
+ center: state.lineOfSight.map.center,
+ zoom: state.lineOfSight.map.zoom,
+ start: state.lineOfSight.map.start,
+ end: state.lineOfSight.map.end,
+ heightA: state.lineOfSight.map.heightA,
+ heightB: state.lineOfSight.map.heightB,
+});
+
+const mapDispatchToProps = (dispatcher: IDispatcher) => ({
+
+
+})
+
+type props = Connect<typeof mapStateToProps, typeof mapDispatchToProps> & {
+ minHeight: GPSProfileResult | undefined;
+ maxHeight: GPSProfileResult | undefined;
+};
+
+const styles = (props: any) => makeStyles({
+ accordion: {padding: 5, position: 'absolute', top: 10, width: props.width, marginLeft: 10, zIndex:1},
+ container: { display: 'flex', flexDirection: "column", marginLeft:10, padding: 5 },
+ caption:{width:'40%'},
+ subTitleRow:{ width: '60%'},
+ titleRowElement:{width: '40%', fontWeight: "bold"},
+ secondRow:{width:'25%'},
+ thirdRow:{width:'20%'}
+ });
+
+const MapInfo: React.FC<props> = (props) =>{
+
+ const [expanded, setExpanded] = React.useState(false);
+ const [width, setWidth] = React.useState(470);
+ const [length, setLength] = React.useState<string | undefined>();
+
+ const classes = styles({width: width})();
+
+ const {start, end, center, zoom, heightA, heightB, minHeight, maxHeight} = props;
+
+ React.useEffect(()=>{
+
+ if(start && end){
+ setLength(calculateDistanceInMeter(start.latitude, start.longitude, end.latitude, end.longitude).toFixed(3))
+
+ }else{
+ setLength(undefined)
+ }
+
+ }, [start, end])
+
+ const handleChange = (event: any, isExpanded: boolean) => {
+ setExpanded(isExpanded);
+ };
+
+
+
+
+ return <Accordion className={classes.accordion} expanded={expanded} onChange={handleChange}>
+ <AccordionSummary
+ expandIcon={<ExpandMoreIcon />}
+ aria-controls="panel1a-content"
+ id="panel1a-header"
+ >
+ <Typography >Map Info</Typography>
+ </AccordionSummary>
+ <AccordionDetails className={classes.container}>
+
+
+ <Typography style={{ fontWeight: "bold", flex: "1" }} >Map Center</Typography>
+
+ <div >
+ <div style={{ display: 'flex', flexDirection: "row" }}>
+ <Typography className={classes.caption}> Longitude</Typography><Typography>{center.longitude}</Typography></div>
+ <div style={{ display: 'flex', flexDirection: "row" }}>
+ <Typography className={classes.caption}> Latitude</Typography><Typography>{center.latitude}</Typography></div>
+ <div style={{ display: 'flex', flexDirection: "row" }}>
+ <Typography className={classes.caption}> Zoom</Typography><Typography> {zoom}</Typography></div>
+
+ </div>
+ <Typography style={{ fontWeight: "bold", flex: "1", marginTop:5 }} >Link</Typography>
+
+ <div>
+ <div style={{ display: 'flex', flexDirection: "row", marginLeft:"38%" }}>
+ <Typography className={classes.titleRowElement}> Start</Typography>
+ <Typography className={classes.titleRowElement}> End</Typography>
+ </div>
+
+ <div style={{ display: 'flex', flexDirection: "row" }}>
+
+ <Typography className={classes.caption}> Longitude</Typography>
+ <Typography className={classes.secondRow}> {start?.longitude.toFixed(3)}</Typography>
+ <Typography className={classes.secondRow}> {end?.longitude.toFixed(3)}</Typography></div>
+
+
+ <div style={{ display: 'flex', flexDirection: "row" }}>
+
+ <Typography className={classes.caption}> Latitude</Typography>
+ <Typography className={classes.secondRow}> {start?.latitude.toFixed(3)}</Typography>
+ <Typography className={classes.secondRow}> {end?.latitude.toFixed(3)}</Typography></div>
+
+
+
+ <div style={{ display: 'flex', flexDirection: "row" }}>
+
+ <Typography className={classes.caption}> Meassured height [m]</Typography>
+ <Typography className={classes.secondRow}> {heightA?.amsl}</Typography>
+ <Typography className={classes.secondRow}> {heightB?.amsl}</Typography>
+ </div>
+
+ <div style={{ display: 'flex', flexDirection: "row" }}>
+
+ <Typography className={classes.caption}> Antenna height [m] </Typography>
+ <Typography className={classes.secondRow}> {heightA?.antennaHeight}</Typography>
+ <Typography className={classes.secondRow}> {heightB?.antennaHeight}</Typography>
+ </div>
+
+ <div style={{ display: 'flex', flexDirection: "row" }}>
+
+ <Typography className={classes.caption}> Length [m]</Typography>
+ <Typography className={classes.secondRow}> {length}</Typography>
+
+ </div>
+
+ <div style={{ display: 'flex', flexDirection: "row" }}>
+
+ <Typography className={classes.caption}> Max height @ position </Typography>
+ <Typography className={classes.thirdRow}> {maxHeight? maxHeight.height+' m': ''}</Typography>
+ <Typography className={classes.thirdRow}> {maxHeight?.gps.longitude.toFixed(3)}</Typography>
+ <Typography className={classes.thirdRow}> {maxHeight?.gps.latitude.toFixed(3)}</Typography>
+ </div>
+
+ <div style={{ display: 'flex', flexDirection: "row" }}>
+
+ <Typography className={classes.caption}> Min height @ position</Typography>
+ <Typography className={classes.thirdRow}> {minHeight? minHeight.height +' m': ''}</Typography>
+ <Typography className={classes.thirdRow}> {minHeight?.gps.longitude.toFixed(3)}</Typography>
+ <Typography className={classes.thirdRow}> {minHeight?.gps.latitude.toFixed(3)}</Typography>
+ </div>
+
+ </div>
+</AccordionDetails>
+</Accordion>
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(MapInfo); \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/config.ts b/sdnr/wt/odlux/apps/lineOfSightApp/src/config.ts
new file mode 100644
index 000000000..bc1e1ff99
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/config.ts
@@ -0,0 +1,48 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+export const URL_BASEPATH="lineOfSight";
+
+export const TERRAIN_URL="/terrain"; //http://10.20.11.163:5200 /terrain
+
+export const TILE_URL="/tiles"; //http://tile.openstreetmap.org /tiles
+
+
+export const OSM_STYLE = {
+ 'version': 8,
+ 'sources': {
+ 'raster-tiles': {
+ 'type': 'raster',
+ 'tiles': [
+ TILE_URL+'/{z}/{x}/{y}.png'
+ ],
+ 'tileSize': 256,
+ 'attribution':
+ '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
+ }
+ },
+ 'layers': [
+ {
+ 'id': 'simple-tiles',
+ 'type': 'raster',
+ 'source': 'raster-tiles',
+ 'minZoom': 0,
+ 'maxZoom': 18
+ }
+ ]
+}; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/handlers/mapHandler.ts b/sdnr/wt/odlux/apps/lineOfSightApp/src/handlers/mapHandler.ts
new file mode 100644
index 000000000..6d11977bf
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/handlers/mapHandler.ts
@@ -0,0 +1,82 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+ import { LatLon } from "../model/LatLon";
+import { IActionHandler } from "../../../../framework/src/flux/action";
+import { SetPassedInValuesAction, SetReachableAction } from "../actions/commonActions";
+import { ClearSavedChartAction, SetChartAction, SetEndpointAction, SetHeightA, SetHeightB, SetMapCenterAction, SetStartPointAction } from "../actions/mapActions";
+import { Height } from "model/Height";
+import { isNullOrUndefined } from "util";
+
+
+
+ export interface IMap {
+ center: LatLon;
+ zoom: number;
+ start: LatLon |null;
+ heightA: Height | null;
+ end: LatLon|null;
+ heightB: Height | null;
+ ready: boolean |null;
+ }
+
+ const initialState: IMap = {
+ center: {latitude:52.4003, longitude:13.0584},
+ zoom: 12,
+ start: null,
+ end: null,
+ ready: null,
+ heightA: null,
+ heightB: null
+
+ }
+
+ export const mapHandler: IActionHandler<IMap> = (state = initialState, action) => {
+ if (action instanceof SetPassedInValuesAction) {
+ state = { ...state, start: action.start, end: action.end, center: action.center, heightA: action.heightA, heightB: action.heightB };
+ }
+ else if(action instanceof SetReachableAction){
+ state = { ...state, ready: action.reachable };
+
+ }else if(action instanceof SetChartAction){
+ state = {...state, start:action.startPoint, end: action.endPoint, heightA: action.heightA, heightB: action.heightB}
+ }
+ else if(action instanceof SetStartPointAction){
+ state = {...state, start:action.startPoint}
+
+ }
+ else if(action instanceof SetEndpointAction){
+ state = {...state, end:action.endPoint}
+
+ }
+ else if(action instanceof SetHeightA){
+ state = {...state, heightA:action.height}
+
+ }
+ else if(action instanceof SetHeightB){
+ state = {...state, heightB:action.height}
+
+ }
+ else if(action instanceof ClearSavedChartAction){
+ state= {...state, start: null, end: null, heightA:null, heightB: null}
+ }else if(action instanceof SetMapCenterAction){
+ state={...state, zoom: action.zoom,center:action.point}
+ }
+
+ return state;
+ } \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/handlers/rootHandler.ts b/sdnr/wt/odlux/apps/lineOfSightApp/src/handlers/rootHandler.ts
new file mode 100644
index 000000000..e7d58c41f
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/handlers/rootHandler.ts
@@ -0,0 +1,48 @@
+/**
+* ============LICENSE_START========================================================================
+* ONAP : ccsdk feature sdnr wt odlux
+* =================================================================================================
+* Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+* =================================================================================================
+* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software distributed under the License
+* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+* or implied. See the License for the specific language governing permissions and limitations under
+* the License.
+* ============LICENSE_END==========================================================================
+*/
+// main state handler
+
+import { combineActionHandler } from '../../../../framework/src/flux/middleware';
+
+// ** do not remove **
+import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
+import { IActionHandler } from '../../../../framework/src/flux/action';
+
+
+import { IMap, mapHandler } from './mapHandler';
+
+export interface ILineOfSightAppStateState {
+ map: IMap;
+}
+
+
+
+
+declare module '../../../../framework/src/store/applicationStore' {
+ interface IApplicationStoreState {
+ lineOfSight: ILineOfSightAppStateState;
+ }
+}
+
+const actionHandlers = {
+ map: mapHandler,
+};
+
+export const lineofSightRootHandler = combineActionHandler<ILineOfSightAppStateState>(actionHandlers);
+export default lineofSightRootHandler;
+
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/hooks/d3.ts b/sdnr/wt/odlux/apps/lineOfSightApp/src/hooks/d3.ts
new file mode 100644
index 000000000..dfebe8605
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/hooks/d3.ts
@@ -0,0 +1,37 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+/* eslint-disable react-hooks/exhaustive-deps */
+import { useEffect, useRef } from 'react';
+import type { DependencyList } from 'react';
+
+import * as d3 from 'd3';
+
+
+type SelectionType = d3.Selection<SVGSVGElement, d3.BaseType, null, undefined>;
+
+export const useD3 = (renderChartFn: (selection: SelectionType) => void, dependencies: DependencyList) => {
+ const ref = useRef<SVGSVGElement>(null);
+
+ useEffect(() => {
+ if (ref.current) renderChartFn(d3.select(ref.current));
+ return () => { };
+ }, dependencies);
+
+ return ref;
+}
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/index.html b/sdnr/wt/odlux/apps/lineOfSightApp/src/index.html
new file mode 100644
index 000000000..6c1478e42
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/index.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
+ <!-- <link rel="stylesheet" href="./vendor.css" > -->
+ <title>LineOfSightApp</title>
+</head>
+
+<body>
+ <div id="app"></div>
+ <script type="text/javascript" src="./require.js"></script>
+ <script type="text/javascript" src="./config.js"></script>
+
+ <script>
+ // run the application
+ require(["app","connectApp","faultApp", "networkMapApp", "lineOfSightApp", "linkCalculationApp"], function (app, connectApp, faultApp, networkMapApp, lineOfSightApp, linkCalculationApp) {
+ connectApp.register();
+ faultApp.register();
+ //configurationApp.register();
+ //linkCalculationApp.register();
+ networkMapApp.register();
+ lineOfSightApp.register();
+ app("./app.tsx").runApplication();
+ });
+ </script>
+</body>
+
+</html> \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/model/GPSProfileResult.ts b/sdnr/wt/odlux/apps/lineOfSightApp/src/model/GPSProfileResult.ts
new file mode 100644
index 000000000..567946bc6
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/model/GPSProfileResult.ts
@@ -0,0 +1,19 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+export type GPSProfileResult = { height: number, gps: { latitude: number, longitude: number }, band: string, zone: number, easting: number, northing: number }; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/model/Height.tsx b/sdnr/wt/odlux/apps/lineOfSightApp/src/model/Height.tsx
new file mode 100644
index 000000000..7014095cb
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/model/Height.tsx
@@ -0,0 +1,22 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+export type Height = {
+ amsl: number;
+ antennaHeight: number;
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/model/LatLon.ts b/sdnr/wt/odlux/apps/lineOfSightApp/src/model/LatLon.ts
new file mode 100644
index 000000000..a447aa52a
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/model/LatLon.ts
@@ -0,0 +1,22 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+export type LatLon ={
+ latitude: number,
+ longitude: number
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/pluginLineOfSight.tsx b/sdnr/wt/odlux/apps/lineOfSightApp/src/pluginLineOfSight.tsx
new file mode 100644
index 000000000..b193cfb22
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/pluginLineOfSight.tsx
@@ -0,0 +1,138 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+// app configuration and main entry point for the app
+
+import * as React from "react";
+import { faRoute } from '@fortawesome/free-solid-svg-icons'; // select app icon
+import applicationManager from '../../../framework/src/services/applicationManager';
+
+
+import { lineofSightRootHandler } from './handlers/rootHandler';
+import MainView from "./views/main";
+import applicationApi from "../../../framework/src/services/applicationApi";
+
+import { Redirect, Route, RouteComponentProps, Switch, useLocation, withRouter } from "react-router-dom";
+import connect, { Connect, IDispatcher } from "../../../framework/src/flux/connect";
+import { IApplicationStoreState } from "../../../framework/src/store/applicationStore";
+import { SetPassedInValues, SetReachableAction } from "./actions/commonActions";
+import { TERRAIN_URL, TILE_URL } from "./config";
+import { isNumber } from "./utils/math";
+
+const mapProps = (state: IApplicationStoreState) => ({
+});
+
+const mapDisp = (dispatcher: IDispatcher) => ({
+ setPassedInValues: (values: (string | null)[]) => dispatcher.dispatch(SetPassedInValues(values)),
+ setReachable: (reachable: boolean) => dispatcher.dispatch(new SetReachableAction(reachable))
+
+});
+
+let lastSearch = "";
+
+const useQuery = () => {
+ return new URLSearchParams(useLocation().search);
+}
+
+
+const LineOfSightApplicationRouteAdapter = connect(mapProps, mapDisp)((props: RouteComponentProps<{ mountId?: string }> & Connect<typeof mapProps, typeof mapDisp>) => {
+
+ let query = useQuery();
+
+ // called when component finshed mounting
+ React.useEffect(() => {
+ extractAndDispatchUrlValues(props.location.search);
+
+ //check tiles/terrain connectivity
+ tryCheckConnection();
+
+ }, []);
+
+
+ const extractAndDispatchUrlValues = (url: string) => {
+
+ if (lastSearch !== url) {
+ lastSearch = url;
+
+ //if mandatory values aren't there, do nothing
+ if (areMandatoryParamsPresent(query)) {
+ const values = extractValuesFromURL(query);
+ props.setPassedInValues(values);
+ }
+ }
+ }
+
+ const tryCheckConnection =() =>{
+ const terrain = fetch(`${TERRAIN_URL}/`);
+ const tiles = fetch(`${TILE_URL}/10/0/0.png`);
+
+ Promise.all([terrain, tiles])
+ .then((result) => {
+ props.setReachable(true);
+
+ })
+ .catch(error=>{
+ console.error("services not reachable.");
+ console.error(error);
+ props.setReachable(false);
+
+ })
+
+ }
+
+ /***
+ *
+ * Checks if lat1, lon1, lat2, lon2 were passed in as url parameters
+ */
+ const areMandatoryParamsPresent = (query: URLSearchParams) => {
+
+ return isNumber(query.get("lat1")) && isNumber(query.get("lon1")) && isNumber(query.get("lat2")) && isNumber(query.get("lon2"))
+
+ }
+
+ const extractValuesFromURL = (query: URLSearchParams) => {
+
+ return [query.get("lat1"), query.get("lon1"), query.get("lat2"), query.get("lon2"), query.get("amslA"), query.get("antennaHeightA"), query.get("amslB"), query.get("antennaHeightB")]
+ }
+
+ return (
+ <MainView />
+ );
+});
+
+
+const LoSRouterApp = withRouter(connect(mapProps, mapDisp)((props: RouteComponentProps & Connect<typeof mapProps, typeof mapDisp>) => {
+
+ return (
+ <Switch>
+ <Route path={`${props.match.path}`} component={LineOfSightApplicationRouteAdapter} />
+ <Redirect to={`${props.match.path}`} />
+ </Switch>
+ )
+}));
+
+export function register() {
+ applicationManager.registerApplication({
+ name: "lineOfSight", // used as name of state as well
+ icon: faRoute,
+ rootActionHandler: lineofSightRootHandler,
+ rootComponent: LoSRouterApp,
+ menuEntry: "Line of Sight"
+ });
+}
+
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/services/heightService.ts b/sdnr/wt/odlux/apps/lineOfSightApp/src/services/heightService.ts
new file mode 100644
index 000000000..8b0535881
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/services/heightService.ts
@@ -0,0 +1,62 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+import { GPSProfileResult } from "../model/GPSProfileResult";
+import { TERRAIN_URL } from "../config";
+import { LatLon } from "../model/LatLon";
+
+export const apiUrlBase="api/Query";
+
+export const getGPSProfile = async (start: LatLon, end: LatLon) => {
+ const url = `${TERRAIN_URL}/${apiUrlBase}/GPSProfileRecords`;
+
+ const result = await fetch(url, {
+ method: "POST",
+ body: JSON.stringify({ start, end }),
+ headers: {
+ 'Content-Type': 'application/json'
+ // 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ });
+ if (result.ok) {
+ const data = await result.json() as GPSProfileResult[];
+ return data;
+ }
+
+ return Number.NaN;
+}
+
+export const getGPSHeight = async (gpsCoord: LatLon) => {
+ const url = `${TERRAIN_URL}/${apiUrlBase}/GPSHeight`;
+
+ const result = await fetch(url, {
+ method: "POST",
+ body: JSON.stringify(gpsCoord),
+ headers: {
+ 'Content-Type': 'application/json'
+ // 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ });
+ if (result.ok) {
+ const data = await result.json() as { height: number };
+ return data.height;
+ }else{
+ return undefined;
+ }
+}
+
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/styles/index.css b/sdnr/wt/odlux/apps/lineOfSightApp/src/styles/index.css
new file mode 100644
index 000000000..ec2585e8c
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/styles/index.css
@@ -0,0 +1,13 @@
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+ sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+code {
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+ monospace;
+}
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/styles/mapbox-gl.css b/sdnr/wt/odlux/apps/lineOfSightApp/src/styles/mapbox-gl.css
new file mode 100644
index 000000000..03c479af9
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/styles/mapbox-gl.css
@@ -0,0 +1 @@
+.mapboxgl-map{font:12px/20px Helvetica Neue,Arial,Helvetica,sans-serif;overflow:hidden;position:relative;-webkit-tap-highlight-color:rgba(0,0,0,0);text-align:left}.mapboxgl-map:-webkit-full-screen{width:100%;height:100%}.mapboxgl-canary{background-color:salmon}.mapboxgl-canvas-container.mapboxgl-interactive,.mapboxgl-ctrl-group button.mapboxgl-ctrl-compass{cursor:-webkit-grab;cursor:-moz-grab;cursor:grab;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.mapboxgl-canvas-container.mapboxgl-interactive.mapboxgl-track-pointer{cursor:pointer}.mapboxgl-canvas-container.mapboxgl-interactive:active,.mapboxgl-ctrl-group button.mapboxgl-ctrl-compass:active{cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing}.mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate,.mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate .mapboxgl-canvas{touch-action:pan-x pan-y}.mapboxgl-canvas-container.mapboxgl-touch-drag-pan,.mapboxgl-canvas-container.mapboxgl-touch-drag-pan .mapboxgl-canvas{touch-action:pinch-zoom}.mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate.mapboxgl-touch-drag-pan,.mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate.mapboxgl-touch-drag-pan .mapboxgl-canvas{touch-action:none}.mapboxgl-ctrl-bottom-left,.mapboxgl-ctrl-bottom-right,.mapboxgl-ctrl-top-left,.mapboxgl-ctrl-top-right{position:absolute;pointer-events:none;z-index:2}.mapboxgl-ctrl-top-left{top:0;left:0}.mapboxgl-ctrl-top-right{top:0;right:0}.mapboxgl-ctrl-bottom-left{bottom:0;left:0}.mapboxgl-ctrl-bottom-right{right:0;bottom:0}.mapboxgl-ctrl{clear:both;pointer-events:auto;transform:translate(0)}.mapboxgl-ctrl-top-left .mapboxgl-ctrl{margin:10px 0 0 10px;float:left}.mapboxgl-ctrl-top-right .mapboxgl-ctrl{margin:10px 10px 0 0;float:right}.mapboxgl-ctrl-bottom-left .mapboxgl-ctrl{margin:0 0 10px 10px;float:left}.mapboxgl-ctrl-bottom-right .mapboxgl-ctrl{margin:0 10px 10px 0;float:right}.mapboxgl-ctrl-group{border-radius:4px;background:#fff}.mapboxgl-ctrl-group:not(:empty){-moz-box-shadow:0 0 2px rgba(0,0,0,.1);-webkit-box-shadow:0 0 2px rgba(0,0,0,.1);box-shadow:0 0 0 2px rgba(0,0,0,.1)}@media (-ms-high-contrast:active){.mapboxgl-ctrl-group:not(:empty){box-shadow:0 0 0 2px ButtonText}}.mapboxgl-ctrl-group button{width:29px;height:29px;display:block;padding:0;outline:none;border:0;box-sizing:border-box;background-color:transparent;cursor:pointer}.mapboxgl-ctrl-group button+button{border-top:1px solid #ddd}.mapboxgl-ctrl button .mapboxgl-ctrl-icon{display:block;width:100%;height:100%;background-repeat:no-repeat;background-position:50%}@media (-ms-high-contrast:active){.mapboxgl-ctrl-icon{background-color:transparent}.mapboxgl-ctrl-group button+button{border-top:1px solid ButtonText}}.mapboxgl-ctrl button::-moz-focus-inner{border:0;padding:0}.mapboxgl-ctrl-group button:focus{box-shadow:0 0 2px 2px #0096ff}.mapboxgl-ctrl button:disabled{cursor:not-allowed}.mapboxgl-ctrl button:disabled .mapboxgl-ctrl-icon{opacity:.25}.mapboxgl-ctrl button:not(:disabled):hover{background-color:rgba(0,0,0,.05)}.mapboxgl-ctrl-group button:focus:focus-visible{box-shadow:0 0 2px 2px #0096ff}.mapboxgl-ctrl-group button:focus:not(:focus-visible){box-shadow:none}.mapboxgl-ctrl-group button:focus:first-child{border-radius:4px 4px 0 0}.mapboxgl-ctrl-group button:focus:last-child{border-radius:0 0 4px 4px}.mapboxgl-ctrl-group button:focus:only-child{border-radius:inherit}.mapboxgl-ctrl button.mapboxgl-ctrl-zoom-out .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23333'%3E%3Cpath d='M10 13c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h9c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13h-9z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-zoom-in .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23333'%3E%3Cpath d='M14.5 8.5c-.75 0-1.5.75-1.5 1.5v3h-3c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h3v3c0 .75.75 1.5 1.5 1.5S16 19.75 16 19v-3h3c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13h-3v-3c0-.75-.75-1.5-1.5-1.5z'/%3E%3C/svg%3E")}@media (-ms-high-contrast:active){.mapboxgl-ctrl button.mapboxgl-ctrl-zoom-out .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23fff'%3E%3Cpath d='M10 13c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h9c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13h-9z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-zoom-in .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23fff'%3E%3Cpath d='M14.5 8.5c-.75 0-1.5.75-1.5 1.5v3h-3c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h3v3c0 .75.75 1.5 1.5 1.5S16 19.75 16 19v-3h3c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13h-3v-3c0-.75-.75-1.5-1.5-1.5z'/%3E%3C/svg%3E")}}@media (-ms-high-contrast:black-on-white){.mapboxgl-ctrl button.mapboxgl-ctrl-zoom-out .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10 13c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h9c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13h-9z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-zoom-in .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M14.5 8.5c-.75 0-1.5.75-1.5 1.5v3h-3c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h3v3c0 .75.75 1.5 1.5 1.5S16 19.75 16 19v-3h3c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13h-3v-3c0-.75-.75-1.5-1.5-1.5z'/%3E%3C/svg%3E")}}.mapboxgl-ctrl button.mapboxgl-ctrl-fullscreen .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23333'%3E%3Cpath d='M24 16v5.5c0 1.75-.75 2.5-2.5 2.5H16v-1l3-1.5-4-5.5 1-1 5.5 4 1.5-3h1zM6 16l1.5 3 5.5-4 1 1-4 5.5 3 1.5v1H7.5C5.75 24 5 23.25 5 21.5V16h1zm7-11v1l-3 1.5 4 5.5-1 1-5.5-4L6 13H5V7.5C5 5.75 5.75 5 7.5 5H13zm11 2.5c0-1.75-.75-2.5-2.5-2.5H16v1l3 1.5-4 5.5 1 1 5.5-4 1.5 3h1V7.5z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-shrink .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M18.5 16c-1.75 0-2.5.75-2.5 2.5V24h1l1.5-3 5.5 4 1-1-4-5.5 3-1.5v-1h-5.5zM13 18.5c0-1.75-.75-2.5-2.5-2.5H5v1l3 1.5L4 24l1 1 5.5-4 1.5 3h1v-5.5zm3-8c0 1.75.75 2.5 2.5 2.5H24v-1l-3-1.5L25 5l-1-1-5.5 4L17 5h-1v5.5zM10.5 13c1.75 0 2.5-.75 2.5-2.5V5h-1l-1.5 3L5 4 4 5l4 5.5L5 12v1h5.5z'/%3E%3C/svg%3E")}@media (-ms-high-contrast:active){.mapboxgl-ctrl button.mapboxgl-ctrl-fullscreen .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23fff'%3E%3Cpath d='M24 16v5.5c0 1.75-.75 2.5-2.5 2.5H16v-1l3-1.5-4-5.5 1-1 5.5 4 1.5-3h1zM6 16l1.5 3 5.5-4 1 1-4 5.5 3 1.5v1H7.5C5.75 24 5 23.25 5 21.5V16h1zm7-11v1l-3 1.5 4 5.5-1 1-5.5-4L6 13H5V7.5C5 5.75 5.75 5 7.5 5H13zm11 2.5c0-1.75-.75-2.5-2.5-2.5H16v1l3 1.5-4 5.5 1 1 5.5-4 1.5 3h1V7.5z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-shrink .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23fff'%3E%3Cpath d='M18.5 16c-1.75 0-2.5.75-2.5 2.5V24h1l1.5-3 5.5 4 1-1-4-5.5 3-1.5v-1h-5.5zM13 18.5c0-1.75-.75-2.5-2.5-2.5H5v1l3 1.5L4 24l1 1 5.5-4 1.5 3h1v-5.5zm3-8c0 1.75.75 2.5 2.5 2.5H24v-1l-3-1.5L25 5l-1-1-5.5 4L17 5h-1v5.5zM10.5 13c1.75 0 2.5-.75 2.5-2.5V5h-1l-1.5 3L5 4 4 5l4 5.5L5 12v1h5.5z'/%3E%3C/svg%3E")}}@media (-ms-high-contrast:black-on-white){.mapboxgl-ctrl button.mapboxgl-ctrl-fullscreen .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M24 16v5.5c0 1.75-.75 2.5-2.5 2.5H16v-1l3-1.5-4-5.5 1-1 5.5 4 1.5-3h1zM6 16l1.5 3 5.5-4 1 1-4 5.5 3 1.5v1H7.5C5.75 24 5 23.25 5 21.5V16h1zm7-11v1l-3 1.5 4 5.5-1 1-5.5-4L6 13H5V7.5C5 5.75 5.75 5 7.5 5H13zm11 2.5c0-1.75-.75-2.5-2.5-2.5H16v1l3 1.5-4 5.5 1 1 5.5-4 1.5 3h1V7.5z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-shrink .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M18.5 16c-1.75 0-2.5.75-2.5 2.5V24h1l1.5-3 5.5 4 1-1-4-5.5 3-1.5v-1h-5.5zM13 18.5c0-1.75-.75-2.5-2.5-2.5H5v1l3 1.5L4 24l1 1 5.5-4 1.5 3h1v-5.5zm3-8c0 1.75.75 2.5 2.5 2.5H24v-1l-3-1.5L25 5l-1-1-5.5 4L17 5h-1v5.5zM10.5 13c1.75 0 2.5-.75 2.5-2.5V5h-1l-1.5 3L5 4 4 5l4 5.5L5 12v1h5.5z'/%3E%3C/svg%3E")}}.mapboxgl-ctrl button.mapboxgl-ctrl-compass .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23333'%3E%3Cpath d='M10.5 14l4-8 4 8h-8z'/%3E%3Cpath d='M10.5 16l4 8 4-8h-8z' fill='%23ccc'/%3E%3C/svg%3E")}@media (-ms-high-contrast:active){.mapboxgl-ctrl button.mapboxgl-ctrl-compass .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23fff'%3E%3Cpath d='M10.5 14l4-8 4 8h-8z'/%3E%3Cpath d='M10.5 16l4 8 4-8h-8z' fill='%23999'/%3E%3C/svg%3E")}}@media (-ms-high-contrast:black-on-white){.mapboxgl-ctrl button.mapboxgl-ctrl-compass .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10.5 14l4-8 4 8h-8z'/%3E%3Cpath d='M10.5 16l4 8 4-8h-8z' fill='%23ccc'/%3E%3C/svg%3E")}}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23333'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate:disabled .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23aaa'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3Cpath d='M14 5l1 1-9 9-1-1 9-9z' fill='red'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-active .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%2333b5e5'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-active-error .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23e58978'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-background .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%2333b5e5'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-background-error .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23e54e33'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-waiting .mapboxgl-ctrl-icon{-webkit-animation:mapboxgl-spin 2s linear infinite;-moz-animation:mapboxgl-spin 2s infinite linear;-o-animation:mapboxgl-spin 2s infinite linear;-ms-animation:mapboxgl-spin 2s infinite linear;animation:mapboxgl-spin 2s linear infinite}@media (-ms-high-contrast:active){.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23fff'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate:disabled .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23999'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3Cpath d='M14 5l1 1-9 9-1-1 9-9z' fill='red'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-active .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%2333b5e5'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-active-error .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23e58978'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-background .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%2333b5e5'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-background-error .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23e54e33'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3C/svg%3E")}}@media (-ms-high-contrast:black-on-white){.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3C/svg%3E")}.mapboxgl-ctrl button.mapboxgl-ctrl-geolocate:disabled .mapboxgl-ctrl-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23666'%3E%3Cpath d='M10 4C9 4 9 5 9 5v.1A5 5 0 005.1 9H5s-1 0-1 1 1 1 1 1h.1A5 5 0 009 14.9v.1s0 1 1 1 1-1 1-1v-.1a5 5 0 003.9-3.9h.1s1 0 1-1-1-1-1-1h-.1A5 5 0 0011 5.1V5s0-1-1-1zm0 2.5a3.5 3.5 0 110 7 3.5 3.5 0 110-7z'/%3E%3Ccircle cx='10' cy='10' r='2'/%3E%3Cpath d='M14 5l1 1-9 9-1-1 9-9z' fill='red'/%3E%3C/svg%3E")}}@-webkit-keyframes mapboxgl-spin{0%{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(1turn)}}@-moz-keyframes mapboxgl-spin{0%{-moz-transform:rotate(0deg)}to{-moz-transform:rotate(1turn)}}@-o-keyframes mapboxgl-spin{0%{-o-transform:rotate(0deg)}to{-o-transform:rotate(1turn)}}@-ms-keyframes mapboxgl-spin{0%{-ms-transform:rotate(0deg)}to{-ms-transform:rotate(1turn)}}@keyframes mapboxgl-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}a.mapboxgl-ctrl-logo{width:88px;height:23px;margin:0 0 -4px -4px;display:block;background-repeat:no-repeat;cursor:pointer;overflow:hidden;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='88' height='23' viewBox='0 0 88 23' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' fill-rule='evenodd'%3E%3Cdefs%3E%3Cpath id='a' d='M11.5 2.25c5.105 0 9.25 4.145 9.25 9.25s-4.145 9.25-9.25 9.25-9.25-4.145-9.25-9.25 4.145-9.25 9.25-9.25zM6.997 15.983c-.051-.338-.828-5.802 2.233-8.873a4.395 4.395 0 013.13-1.28c1.27 0 2.49.51 3.39 1.42.91.9 1.42 2.12 1.42 3.39 0 1.18-.449 2.301-1.28 3.13C12.72 16.93 7 16 7 16l-.003-.017zM15.3 10.5l-2 .8-.8 2-.8-2-2-.8 2-.8.8-2 .8 2 2 .8z'/%3E%3Cpath id='b' d='M50.63 8c.13 0 .23.1.23.23V9c.7-.76 1.7-1.18 2.73-1.18 2.17 0 3.95 1.85 3.95 4.17s-1.77 4.19-3.94 4.19c-1.04 0-2.03-.43-2.74-1.18v3.77c0 .13-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V8.23c0-.12.1-.23.23-.23h1.4zm-3.86.01c.01 0 .01 0 .01-.01.13 0 .22.1.22.22v7.55c0 .12-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V15c-.7.76-1.69 1.19-2.73 1.19-2.17 0-3.94-1.87-3.94-4.19 0-2.32 1.77-4.19 3.94-4.19 1.03 0 2.02.43 2.73 1.18v-.75c0-.12.1-.23.23-.23h1.4zm26.375-.19a4.24 4.24 0 00-4.16 3.29c-.13.59-.13 1.19 0 1.77a4.233 4.233 0 004.17 3.3c2.35 0 4.26-1.87 4.26-4.19 0-2.32-1.9-4.17-4.27-4.17zM60.63 5c.13 0 .23.1.23.23v3.76c.7-.76 1.7-1.18 2.73-1.18 1.88 0 3.45 1.4 3.84 3.28.13.59.13 1.2 0 1.8-.39 1.88-1.96 3.29-3.84 3.29-1.03 0-2.02-.43-2.73-1.18v.77c0 .12-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V5.23c0-.12.1-.23.23-.23h1.4zm-34 11h-1.4c-.13 0-.23-.11-.23-.23V8.22c.01-.13.1-.22.23-.22h1.4c.13 0 .22.11.23.22v.68c.5-.68 1.3-1.09 2.16-1.1h.03c1.09 0 2.09.6 2.6 1.55.45-.95 1.4-1.55 2.44-1.56 1.62 0 2.93 1.25 2.9 2.78l.03 5.2c0 .13-.1.23-.23.23h-1.41c-.13 0-.23-.11-.23-.23v-4.59c0-.98-.74-1.71-1.62-1.71-.8 0-1.46.7-1.59 1.62l.01 4.68c0 .13-.11.23-.23.23h-1.41c-.13 0-.23-.11-.23-.23v-4.59c0-.98-.74-1.71-1.62-1.71-.85 0-1.54.79-1.6 1.8v4.5c0 .13-.1.23-.23.23zm53.615 0h-1.61c-.04 0-.08-.01-.12-.03-.09-.06-.13-.19-.06-.28l2.43-3.71-2.39-3.65a.213.213 0 01-.03-.12c0-.12.09-.21.21-.21h1.61c.13 0 .24.06.3.17l1.41 2.37 1.4-2.37a.34.34 0 01.3-.17h1.6c.04 0 .08.01.12.03.09.06.13.19.06.28l-2.37 3.65 2.43 3.7c0 .05.01.09.01.13 0 .12-.09.21-.21.21h-1.61c-.13 0-.24-.06-.3-.17l-1.44-2.42-1.44 2.42a.34.34 0 01-.3.17zm-7.12-1.49c-1.33 0-2.42-1.12-2.42-2.51 0-1.39 1.08-2.52 2.42-2.52 1.33 0 2.42 1.12 2.42 2.51 0 1.39-1.08 2.51-2.42 2.52zm-19.865 0c-1.32 0-2.39-1.11-2.42-2.48v-.07c.02-1.38 1.09-2.49 2.4-2.49 1.32 0 2.41 1.12 2.41 2.51 0 1.39-1.07 2.52-2.39 2.53zm-8.11-2.48c-.01 1.37-1.09 2.47-2.41 2.47s-2.42-1.12-2.42-2.51c0-1.39 1.08-2.52 2.4-2.52 1.33 0 2.39 1.11 2.41 2.48l.02.08zm18.12 2.47c-1.32 0-2.39-1.11-2.41-2.48v-.06c.02-1.38 1.09-2.48 2.41-2.48s2.42 1.12 2.42 2.51c0 1.39-1.09 2.51-2.42 2.51z'/%3E%3C/defs%3E%3Cmask id='c'%3E%3Crect width='100%25' height='100%25' fill='%23fff'/%3E%3Cuse xlink:href='%23a'/%3E%3Cuse xlink:href='%23b'/%3E%3C/mask%3E%3Cg opacity='.3' stroke='%23000' stroke-width='3'%3E%3Ccircle mask='url(%23c)' cx='11.5' cy='11.5' r='9.25'/%3E%3Cuse xlink:href='%23b' mask='url(%23c)'/%3E%3C/g%3E%3Cg opacity='.9' fill='%23fff'%3E%3Cuse xlink:href='%23a'/%3E%3Cuse xlink:href='%23b'/%3E%3C/g%3E%3C/svg%3E")}a.mapboxgl-ctrl-logo.mapboxgl-compact{width:23px}@media (-ms-high-contrast:active){a.mapboxgl-ctrl-logo{background-color:transparent;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='88' height='23' viewBox='0 0 88 23' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' fill-rule='evenodd'%3E%3Cdefs%3E%3Cpath id='a' d='M11.5 2.25c5.105 0 9.25 4.145 9.25 9.25s-4.145 9.25-9.25 9.25-9.25-4.145-9.25-9.25 4.145-9.25 9.25-9.25zM6.997 15.983c-.051-.338-.828-5.802 2.233-8.873a4.395 4.395 0 013.13-1.28c1.27 0 2.49.51 3.39 1.42.91.9 1.42 2.12 1.42 3.39 0 1.18-.449 2.301-1.28 3.13C12.72 16.93 7 16 7 16l-.003-.017zM15.3 10.5l-2 .8-.8 2-.8-2-2-.8 2-.8.8-2 .8 2 2 .8z'/%3E%3Cpath id='b' d='M50.63 8c.13 0 .23.1.23.23V9c.7-.76 1.7-1.18 2.73-1.18 2.17 0 3.95 1.85 3.95 4.17s-1.77 4.19-3.94 4.19c-1.04 0-2.03-.43-2.74-1.18v3.77c0 .13-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V8.23c0-.12.1-.23.23-.23h1.4zm-3.86.01c.01 0 .01 0 .01-.01.13 0 .22.1.22.22v7.55c0 .12-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V15c-.7.76-1.69 1.19-2.73 1.19-2.17 0-3.94-1.87-3.94-4.19 0-2.32 1.77-4.19 3.94-4.19 1.03 0 2.02.43 2.73 1.18v-.75c0-.12.1-.23.23-.23h1.4zm26.375-.19a4.24 4.24 0 00-4.16 3.29c-.13.59-.13 1.19 0 1.77a4.233 4.233 0 004.17 3.3c2.35 0 4.26-1.87 4.26-4.19 0-2.32-1.9-4.17-4.27-4.17zM60.63 5c.13 0 .23.1.23.23v3.76c.7-.76 1.7-1.18 2.73-1.18 1.88 0 3.45 1.4 3.84 3.28.13.59.13 1.2 0 1.8-.39 1.88-1.96 3.29-3.84 3.29-1.03 0-2.02-.43-2.73-1.18v.77c0 .12-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V5.23c0-.12.1-.23.23-.23h1.4zm-34 11h-1.4c-.13 0-.23-.11-.23-.23V8.22c.01-.13.1-.22.23-.22h1.4c.13 0 .22.11.23.22v.68c.5-.68 1.3-1.09 2.16-1.1h.03c1.09 0 2.09.6 2.6 1.55.45-.95 1.4-1.55 2.44-1.56 1.62 0 2.93 1.25 2.9 2.78l.03 5.2c0 .13-.1.23-.23.23h-1.41c-.13 0-.23-.11-.23-.23v-4.59c0-.98-.74-1.71-1.62-1.71-.8 0-1.46.7-1.59 1.62l.01 4.68c0 .13-.11.23-.23.23h-1.41c-.13 0-.23-.11-.23-.23v-4.59c0-.98-.74-1.71-1.62-1.71-.85 0-1.54.79-1.6 1.8v4.5c0 .13-.1.23-.23.23zm53.615 0h-1.61c-.04 0-.08-.01-.12-.03-.09-.06-.13-.19-.06-.28l2.43-3.71-2.39-3.65a.213.213 0 01-.03-.12c0-.12.09-.21.21-.21h1.61c.13 0 .24.06.3.17l1.41 2.37 1.4-2.37a.34.34 0 01.3-.17h1.6c.04 0 .08.01.12.03.09.06.13.19.06.28l-2.37 3.65 2.43 3.7c0 .05.01.09.01.13 0 .12-.09.21-.21.21h-1.61c-.13 0-.24-.06-.3-.17l-1.44-2.42-1.44 2.42a.34.34 0 01-.3.17zm-7.12-1.49c-1.33 0-2.42-1.12-2.42-2.51 0-1.39 1.08-2.52 2.42-2.52 1.33 0 2.42 1.12 2.42 2.51 0 1.39-1.08 2.51-2.42 2.52zm-19.865 0c-1.32 0-2.39-1.11-2.42-2.48v-.07c.02-1.38 1.09-2.49 2.4-2.49 1.32 0 2.41 1.12 2.41 2.51 0 1.39-1.07 2.52-2.39 2.53zm-8.11-2.48c-.01 1.37-1.09 2.47-2.41 2.47s-2.42-1.12-2.42-2.51c0-1.39 1.08-2.52 2.4-2.52 1.33 0 2.39 1.11 2.41 2.48l.02.08zm18.12 2.47c-1.32 0-2.39-1.11-2.41-2.48v-.06c.02-1.38 1.09-2.48 2.41-2.48s2.42 1.12 2.42 2.51c0 1.39-1.09 2.51-2.42 2.51z'/%3E%3C/defs%3E%3Cmask id='c'%3E%3Crect width='100%25' height='100%25' fill='%23fff'/%3E%3Cuse xlink:href='%23a'/%3E%3Cuse xlink:href='%23b'/%3E%3C/mask%3E%3Cg stroke='%23000' stroke-width='3'%3E%3Ccircle mask='url(%23c)' cx='11.5' cy='11.5' r='9.25'/%3E%3Cuse xlink:href='%23b' mask='url(%23c)'/%3E%3C/g%3E%3Cg fill='%23fff'%3E%3Cuse xlink:href='%23a'/%3E%3Cuse xlink:href='%23b'/%3E%3C/g%3E%3C/svg%3E")}}@media (-ms-high-contrast:black-on-white){a.mapboxgl-ctrl-logo{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='88' height='23' viewBox='0 0 88 23' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' fill-rule='evenodd'%3E%3Cdefs%3E%3Cpath id='a' d='M11.5 2.25c5.105 0 9.25 4.145 9.25 9.25s-4.145 9.25-9.25 9.25-9.25-4.145-9.25-9.25 4.145-9.25 9.25-9.25zM6.997 15.983c-.051-.338-.828-5.802 2.233-8.873a4.395 4.395 0 013.13-1.28c1.27 0 2.49.51 3.39 1.42.91.9 1.42 2.12 1.42 3.39 0 1.18-.449 2.301-1.28 3.13C12.72 16.93 7 16 7 16l-.003-.017zM15.3 10.5l-2 .8-.8 2-.8-2-2-.8 2-.8.8-2 .8 2 2 .8z'/%3E%3Cpath id='b' d='M50.63 8c.13 0 .23.1.23.23V9c.7-.76 1.7-1.18 2.73-1.18 2.17 0 3.95 1.85 3.95 4.17s-1.77 4.19-3.94 4.19c-1.04 0-2.03-.43-2.74-1.18v3.77c0 .13-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V8.23c0-.12.1-.23.23-.23h1.4zm-3.86.01c.01 0 .01 0 .01-.01.13 0 .22.1.22.22v7.55c0 .12-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V15c-.7.76-1.69 1.19-2.73 1.19-2.17 0-3.94-1.87-3.94-4.19 0-2.32 1.77-4.19 3.94-4.19 1.03 0 2.02.43 2.73 1.18v-.75c0-.12.1-.23.23-.23h1.4zm26.375-.19a4.24 4.24 0 00-4.16 3.29c-.13.59-.13 1.19 0 1.77a4.233 4.233 0 004.17 3.3c2.35 0 4.26-1.87 4.26-4.19 0-2.32-1.9-4.17-4.27-4.17zM60.63 5c.13 0 .23.1.23.23v3.76c.7-.76 1.7-1.18 2.73-1.18 1.88 0 3.45 1.4 3.84 3.28.13.59.13 1.2 0 1.8-.39 1.88-1.96 3.29-3.84 3.29-1.03 0-2.02-.43-2.73-1.18v.77c0 .12-.1.23-.23.23h-1.4c-.13 0-.23-.1-.23-.23V5.23c0-.12.1-.23.23-.23h1.4zm-34 11h-1.4c-.13 0-.23-.11-.23-.23V8.22c.01-.13.1-.22.23-.22h1.4c.13 0 .22.11.23.22v.68c.5-.68 1.3-1.09 2.16-1.1h.03c1.09 0 2.09.6 2.6 1.55.45-.95 1.4-1.55 2.44-1.56 1.62 0 2.93 1.25 2.9 2.78l.03 5.2c0 .13-.1.23-.23.23h-1.41c-.13 0-.23-.11-.23-.23v-4.59c0-.98-.74-1.71-1.62-1.71-.8 0-1.46.7-1.59 1.62l.01 4.68c0 .13-.11.23-.23.23h-1.41c-.13 0-.23-.11-.23-.23v-4.59c0-.98-.74-1.71-1.62-1.71-.85 0-1.54.79-1.6 1.8v4.5c0 .13-.1.23-.23.23zm53.615 0h-1.61c-.04 0-.08-.01-.12-.03-.09-.06-.13-.19-.06-.28l2.43-3.71-2.39-3.65a.213.213 0 01-.03-.12c0-.12.09-.21.21-.21h1.61c.13 0 .24.06.3.17l1.41 2.37 1.4-2.37a.34.34 0 01.3-.17h1.6c.04 0 .08.01.12.03.09.06.13.19.06.28l-2.37 3.65 2.43 3.7c0 .05.01.09.01.13 0 .12-.09.21-.21.21h-1.61c-.13 0-.24-.06-.3-.17l-1.44-2.42-1.44 2.42a.34.34 0 01-.3.17zm-7.12-1.49c-1.33 0-2.42-1.12-2.42-2.51 0-1.39 1.08-2.52 2.42-2.52 1.33 0 2.42 1.12 2.42 2.51 0 1.39-1.08 2.51-2.42 2.52zm-19.865 0c-1.32 0-2.39-1.11-2.42-2.48v-.07c.02-1.38 1.09-2.49 2.4-2.49 1.32 0 2.41 1.12 2.41 2.51 0 1.39-1.07 2.52-2.39 2.53zm-8.11-2.48c-.01 1.37-1.09 2.47-2.41 2.47s-2.42-1.12-2.42-2.51c0-1.39 1.08-2.52 2.4-2.52 1.33 0 2.39 1.11 2.41 2.48l.02.08zm18.12 2.47c-1.32 0-2.39-1.11-2.41-2.48v-.06c.02-1.38 1.09-2.48 2.41-2.48s2.42 1.12 2.42 2.51c0 1.39-1.09 2.51-2.42 2.51z'/%3E%3C/defs%3E%3Cmask id='c'%3E%3Crect width='100%25' height='100%25' fill='%23fff'/%3E%3Cuse xlink:href='%23a'/%3E%3Cuse xlink:href='%23b'/%3E%3C/mask%3E%3Cg stroke='%23fff' stroke-width='3' fill='%23fff'%3E%3Ccircle mask='url(%23c)' cx='11.5' cy='11.5' r='9.25'/%3E%3Cuse xlink:href='%23b' mask='url(%23c)'/%3E%3C/g%3E%3Cuse xlink:href='%23a'/%3E%3Cuse xlink:href='%23b'/%3E%3C/svg%3E")}}.mapboxgl-ctrl.mapboxgl-ctrl-attrib{padding:0 5px;background-color:hsla(0,0%,100%,.5);margin:0}@media screen{.mapboxgl-ctrl-attrib.mapboxgl-compact{min-height:20px;padding:0;margin:10px;position:relative;background-color:#fff;border-radius:3px 12px 12px 3px}.mapboxgl-ctrl-attrib.mapboxgl-compact:hover{padding:2px 24px 2px 4px;visibility:visible;margin-top:6px}.mapboxgl-ctrl-bottom-left>.mapboxgl-ctrl-attrib.mapboxgl-compact:hover,.mapboxgl-ctrl-top-left>.mapboxgl-ctrl-attrib.mapboxgl-compact:hover{padding:2px 4px 2px 24px;border-radius:12px 3px 3px 12px}.mapboxgl-ctrl-attrib.mapboxgl-compact .mapboxgl-ctrl-attrib-inner{display:none}.mapboxgl-ctrl-attrib.mapboxgl-compact:hover .mapboxgl-ctrl-attrib-inner{display:block}.mapboxgl-ctrl-attrib.mapboxgl-compact:after{content:"";cursor:pointer;position:absolute;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='24' height='24' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill-rule='evenodd'%3E%3Cpath d='M4 10a6 6 0 1012 0 6 6 0 10-12 0m5-3a1 1 0 102 0 1 1 0 10-2 0m0 3a1 1 0 112 0v3a1 1 0 11-2 0'/%3E%3C/svg%3E");background-color:hsla(0,0%,100%,.5);width:24px;height:24px;box-sizing:border-box;border-radius:12px}.mapboxgl-ctrl-bottom-right>.mapboxgl-ctrl-attrib.mapboxgl-compact:after{bottom:0;right:0}.mapboxgl-ctrl-top-right>.mapboxgl-ctrl-attrib.mapboxgl-compact:after{top:0;right:0}.mapboxgl-ctrl-top-left>.mapboxgl-ctrl-attrib.mapboxgl-compact:after{top:0;left:0}.mapboxgl-ctrl-bottom-left>.mapboxgl-ctrl-attrib.mapboxgl-compact:after{bottom:0;left:0}}@media screen and (-ms-high-contrast:active){.mapboxgl-ctrl-attrib.mapboxgl-compact:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='24' height='24' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill-rule='evenodd' fill='%23fff'%3E%3Cpath d='M4 10a6 6 0 1012 0 6 6 0 10-12 0m5-3a1 1 0 102 0 1 1 0 10-2 0m0 3a1 1 0 112 0v3a1 1 0 11-2 0'/%3E%3C/svg%3E")}}@media screen and (-ms-high-contrast:black-on-white){.mapboxgl-ctrl-attrib.mapboxgl-compact:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='24' height='24' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill-rule='evenodd'%3E%3Cpath d='M4 10a6 6 0 1012 0 6 6 0 10-12 0m5-3a1 1 0 102 0 1 1 0 10-2 0m0 3a1 1 0 112 0v3a1 1 0 11-2 0'/%3E%3C/svg%3E")}}.mapboxgl-ctrl-attrib a{color:rgba(0,0,0,.75);text-decoration:none}.mapboxgl-ctrl-attrib a:hover{color:inherit;text-decoration:underline}.mapboxgl-ctrl-attrib .mapbox-improve-map{font-weight:700;margin-left:2px}.mapboxgl-attrib-empty{display:none}.mapboxgl-ctrl-scale{background-color:hsla(0,0%,100%,.75);font-size:10px;border:2px solid #333;border-top:#333;padding:0 5px;color:#333;box-sizing:border-box}.mapboxgl-popup{position:absolute;top:0;left:0;display:-webkit-flex;display:flex;will-change:transform;pointer-events:none}.mapboxgl-popup-anchor-top,.mapboxgl-popup-anchor-top-left,.mapboxgl-popup-anchor-top-right{-webkit-flex-direction:column;flex-direction:column}.mapboxgl-popup-anchor-bottom,.mapboxgl-popup-anchor-bottom-left,.mapboxgl-popup-anchor-bottom-right{-webkit-flex-direction:column-reverse;flex-direction:column-reverse}.mapboxgl-popup-anchor-left{-webkit-flex-direction:row;flex-direction:row}.mapboxgl-popup-anchor-right{-webkit-flex-direction:row-reverse;flex-direction:row-reverse}.mapboxgl-popup-tip{width:0;height:0;border:10px solid transparent;z-index:1}.mapboxgl-popup-anchor-top .mapboxgl-popup-tip{-webkit-align-self:center;align-self:center;border-top:none;border-bottom-color:#fff}.mapboxgl-popup-anchor-top-left .mapboxgl-popup-tip{-webkit-align-self:flex-start;align-self:flex-start;border-top:none;border-left:none;border-bottom-color:#fff}.mapboxgl-popup-anchor-top-right .mapboxgl-popup-tip{-webkit-align-self:flex-end;align-self:flex-end;border-top:none;border-right:none;border-bottom-color:#fff}.mapboxgl-popup-anchor-bottom .mapboxgl-popup-tip{-webkit-align-self:center;align-self:center;border-bottom:none;border-top-color:#fff}.mapboxgl-popup-anchor-bottom-left .mapboxgl-popup-tip{-webkit-align-self:flex-start;align-self:flex-start;border-bottom:none;border-left:none;border-top-color:#fff}.mapboxgl-popup-anchor-bottom-right .mapboxgl-popup-tip{-webkit-align-self:flex-end;align-self:flex-end;border-bottom:none;border-right:none;border-top-color:#fff}.mapboxgl-popup-anchor-left .mapboxgl-popup-tip{-webkit-align-self:center;align-self:center;border-left:none;border-right-color:#fff}.mapboxgl-popup-anchor-right .mapboxgl-popup-tip{-webkit-align-self:center;align-self:center;border-right:none;border-left-color:#fff}.mapboxgl-popup-close-button{position:absolute;right:0;top:0;border:0;border-radius:0 3px 0 0;cursor:pointer;background-color:transparent}.mapboxgl-popup-close-button:hover{background-color:rgba(0,0,0,.05)}.mapboxgl-popup-content{position:relative;background:#fff;border-radius:3px;box-shadow:0 1px 2px rgba(0,0,0,.1);padding:10px 10px 15px;pointer-events:auto}.mapboxgl-popup-anchor-top-left .mapboxgl-popup-content{border-top-left-radius:0}.mapboxgl-popup-anchor-top-right .mapboxgl-popup-content{border-top-right-radius:0}.mapboxgl-popup-anchor-bottom-left .mapboxgl-popup-content{border-bottom-left-radius:0}.mapboxgl-popup-anchor-bottom-right .mapboxgl-popup-content{border-bottom-right-radius:0}.mapboxgl-popup-track-pointer{display:none}.mapboxgl-popup-track-pointer *{pointer-events:none;user-select:none}.mapboxgl-map:hover .mapboxgl-popup-track-pointer{display:flex}.mapboxgl-map:active .mapboxgl-popup-track-pointer{display:none}.mapboxgl-marker{position:absolute;top:0;left:0;will-change:transform}.mapboxgl-user-location-dot,.mapboxgl-user-location-dot:before{background-color:#1da1f2;width:15px;height:15px;border-radius:50%}.mapboxgl-user-location-dot:before{content:"";position:absolute;-webkit-animation:mapboxgl-user-location-dot-pulse 2s infinite;-moz-animation:mapboxgl-user-location-dot-pulse 2s infinite;-ms-animation:mapboxgl-user-location-dot-pulse 2s infinite;animation:mapboxgl-user-location-dot-pulse 2s infinite}.mapboxgl-user-location-dot:after{border-radius:50%;border:2px solid #fff;content:"";height:19px;left:-2px;position:absolute;top:-2px;width:19px;box-sizing:border-box;box-shadow:0 0 3px rgba(0,0,0,.35)}@-webkit-keyframes mapboxgl-user-location-dot-pulse{0%{-webkit-transform:scale(1);opacity:1}70%{-webkit-transform:scale(3);opacity:0}to{-webkit-transform:scale(1);opacity:0}}@-ms-keyframes mapboxgl-user-location-dot-pulse{0%{-ms-transform:scale(1);opacity:1}70%{-ms-transform:scale(3);opacity:0}to{-ms-transform:scale(1);opacity:0}}@keyframes mapboxgl-user-location-dot-pulse{0%{transform:scale(1);opacity:1}70%{transform:scale(3);opacity:0}to{transform:scale(1);opacity:0}}.mapboxgl-user-location-dot-stale{background-color:#aaa}.mapboxgl-user-location-dot-stale:after{display:none}.mapboxgl-user-location-accuracy-circle{background-color:rgba(29,161,242,.2);width:1px;height:1px;border-radius:100%}.mapboxgl-crosshair,.mapboxgl-crosshair .mapboxgl-interactive,.mapboxgl-crosshair .mapboxgl-interactive:active{cursor:crosshair}.mapboxgl-boxzoom{position:absolute;top:0;left:0;width:0;height:0;background:#fff;border:2px dotted #202020;opacity:.5}@media print{.mapbox-improve-map{display:none}} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/utils/map.ts b/sdnr/wt/odlux/apps/lineOfSightApp/src/utils/map.ts
new file mode 100644
index 000000000..abdd27ed2
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/utils/map.ts
@@ -0,0 +1,103 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+import * as mapboxgl from "mapbox-gl";
+import { LatLon } from "../model/LatLon";
+
+
+export const addBaseSource = (map : mapboxgl.Map, name: string) =>{
+
+ if(!map.getSource(name))
+
+ map.addSource(name, {
+ type: 'geojson',
+ data: { type: "FeatureCollection", features: [] }
+ });
+
+}
+
+export const addPoint = (map : mapboxgl.Map, point: LatLon) =>{
+ const json = `{
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "Point",
+ "coordinates":
+ [${point.longitude}, ${point.latitude}]
+ }
+ }`;
+
+
+ (map.getSource("route") as mapboxgl.GeoJSONSource).setData(JSON.parse(json));
+}
+
+export const addBaseLayer = (map: mapboxgl.Map, sourceName: string) =>{
+
+ if(!map.getLayer('line'))
+ map.addLayer({
+ 'id': 'line',
+ 'type': 'line',
+ 'source': sourceName,
+ 'layout': {
+ 'line-join': 'round',
+ 'line-cap': 'round'
+ },
+ 'paint': {
+ 'line-color': '#88A',
+ 'line-width': 6,
+ 'line-opacity': 0.75
+ }
+ });
+
+ if(!map.getLayer('points'))
+ map.addLayer({
+ id: 'points',
+ type: 'circle',
+ source: sourceName,
+ paint: {
+ 'circle-radius': 5,
+ 'circle-color': '#223b53',
+ 'circle-stroke-color': '#225ba3',
+ 'circle-stroke-width': 3,
+ 'circle-opacity': 0.5
+ }
+ });
+}
+
+export const calculateDistanceInMeter = (lat1: number, lon1: number, lat2: number, lon2: number) => {
+ const lonRad1 = toRad(lon1);
+ const latRad1 = toRad(lat1);
+ const lonRad2 = toRad(lon2);
+ const latRad2 = toRad(lat2);
+
+ const dLon = lonRad2 - lonRad1;
+ const dLat = latRad2 - latRad1;
+ const a = Math.pow(Math.sin(dLat / 2), 2) +
+ Math.cos(latRad1) * Math.cos(latRad2) *
+ Math.pow(Math.sin(dLon / 2), 2);
+
+ const c = 2 * Math.asin(Math.sqrt(a));
+
+ return 6378 * c;
+
+ }
+
+ function toRad(value: number) {
+ return (value * Math.PI) / 180;
+ }
+ \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/utils/math.ts b/sdnr/wt/odlux/apps/lineOfSightApp/src/utils/math.ts
new file mode 100644
index 000000000..9e0447b97
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/utils/math.ts
@@ -0,0 +1,30 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+export const max = <T,>(a: T[], p: (v: T) => Number) => a.reduce<T>((m, x) => p(m) > p(x) ? m : x, a[0]);
+export const min = <T,>(a: T[], p: (v: T) => Number) => a.reduce<T>((m, x) => p(m) < p(x) ? m : x, a[0]);
+
+export const isNumber = (value: string|null) =>{
+
+ if(!value){
+ return false;
+ }else{
+ const num = Number(value);
+ return !isNaN(num);
+ }
+ } \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src/views/main.tsx b/sdnr/wt/odlux/apps/lineOfSightApp/src/views/main.tsx
new file mode 100644
index 000000000..bbe6f34e6
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src/views/main.tsx
@@ -0,0 +1,30 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+
+import * as React from 'react';
+import Map from '../components/map';
+
+function MainView() {
+ return (
+ <div className="App" style={{height:"100%"}}>
+ <Map />
+ </div>
+ );
+}
+
+export default MainView; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java b/sdnr/wt/odlux/apps/lineOfSightApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java
new file mode 100644
index 000000000..43b072c4b
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java
@@ -0,0 +1,68 @@
+/*
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+package org.onap.ccsdk.features.sdnr.wt.odlux.bundles;
+
+import org.onap.ccsdk.features.sdnr.wt.odlux.model.bundles.OdluxBundle;
+import org.onap.ccsdk.features.sdnr.wt.odlux.model.bundles.OdluxBundleLoader;
+
+public class MyOdluxBundle extends OdluxBundle {
+
+ @Override
+ public void initialize() {
+ super.initialize();
+ }
+
+ @Override
+ public void clean() {
+ super.clean();
+ }
+
+ @Override
+ public String getResourceFileContent(String filename) {
+ return super.getResourceFileContent(filename);
+ }
+
+ @Override
+ public boolean hasResource(String filename) {
+ return super.hasResource(filename);
+ }
+
+ @Override
+ public void setBundleName(String bundleName) {
+ super.setBundleName(bundleName);
+ }
+
+ @Override
+ public void setLoader(OdluxBundleLoader loader) {
+ super.setLoader(loader);
+ }
+
+ @Override
+ public String getBundleName() {
+ return super.getBundleName();
+ }
+
+ @Override
+ public OdluxBundleLoader getLoader() {
+ return super.getLoader();
+ }
+
+ public MyOdluxBundle() {
+ super();
+ }
+}
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml b/sdnr/wt/odlux/apps/lineOfSightApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644
index 000000000..982379dda
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -0,0 +1,9 @@
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+ <reference id="loadersvc" availability="mandatory" activation="eager" interface="org.onap.ccsdk.features.sdnr.wt.odlux.model.bundles.OdluxBundleLoader"/>
+
+ <bean id="bundle" init-method="initialize" destroy-method="clean" class="org.onap.ccsdk.features.sdnr.wt.odlux.bundles.MyOdluxBundle">
+ <property name="loader" ref="loadersvc"/>
+ <property name="bundleName" value="lineOfSightApp"/>
+ <property name="index" value="130"/>
+ </bean>
+</blueprint> \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src2/test/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/test/TestBundleRes.java b/sdnr/wt/odlux/apps/lineOfSightApp/src2/test/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/test/TestBundleRes.java
new file mode 100644
index 000000000..c319bb189
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src2/test/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/test/TestBundleRes.java
@@ -0,0 +1,46 @@
+/*
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ * ============LICENSE_END==========================================================================
+ */
+package org.onap.ccsdk.features.sdnr.wt.odlux.bundles.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.odlux.OdluxBundleLoaderImpl;
+import org.onap.ccsdk.features.sdnr.wt.odlux.bundles.MyOdluxBundle;
+
+public class TestBundleRes {
+
+ @Test
+ public void test() {
+ OdluxBundleLoaderImpl loader = OdluxBundleLoaderImpl.getInstance();
+ MyOdluxBundle b = new MyOdluxBundle();
+ b.setLoader(loader);
+ b.setIndex(0);
+ b.setBundleName("abc");
+ b.initialize();
+ assertTrue(loader.getNumberOfBundles()==1);
+ assertNotNull(b.getLoader());
+ assertEquals("abc",b.getBundleName());
+ assertTrue(b.hasResource("test.js"));
+ assertNotNull(b.getResourceFileContent("test.js"));
+ b.clean();
+ assertTrue(loader.getNumberOfBundles()==0);
+ }
+
+}
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/src2/test/resources/test.js b/sdnr/wt/odlux/apps/lineOfSightApp/src2/test/resources/test.js
new file mode 100644
index 000000000..b47fdc39f
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/src2/test/resources/test.js
@@ -0,0 +1,5 @@
+asdac sad
+as
+d
+sad
+ sadfa \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/tsconfig.json b/sdnr/wt/odlux/apps/lineOfSightApp/tsconfig.json
new file mode 100644
index 000000000..a66b5d828
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/tsconfig.json
@@ -0,0 +1,37 @@
+{
+ "compilerOptions": {
+ "baseUrl": "./src",
+ "outDir": "./dist",
+ "sourceMap": true,
+ "forceConsistentCasingInFileNames": true,
+ "allowSyntheticDefaultImports": false,
+ "allowUnreachableCode": false,
+ "allowUnusedLabels": false,
+ "noFallthroughCasesInSwitch": true,
+ "noImplicitAny": true,
+ "noImplicitReturns": true,
+ "noImplicitThis": true,
+ "strictNullChecks": true,
+ "pretty": true,
+ "newLine": "LF",
+ "module": "es2015",
+ "target": "es2016",
+ "moduleResolution": "node",
+ "experimentalDecorators": true,
+ "jsx": "preserve",
+ "lib": [
+ "dom",
+ "es2015",
+ "es2016"
+ ],
+ "types": [
+ "prop-types",
+ "react",
+ "react-dom"
+ ]
+ },
+ "exclude": [
+ "dist",
+ "node_modules"
+ ]
+}
diff --git a/sdnr/wt/odlux/apps/lineOfSightApp/webpack.config.js b/sdnr/wt/odlux/apps/lineOfSightApp/webpack.config.js
new file mode 100644
index 000000000..54ba1b499
--- /dev/null
+++ b/sdnr/wt/odlux/apps/lineOfSightApp/webpack.config.js
@@ -0,0 +1,211 @@
+/**
+ * Webpack 4 configuration file
+ * see https://webpack.js.org/configuration/
+ * see https://webpack.js.org/configuration/dev-server/
+ */
+
+"use strict";
+
+const path = require("path");
+const webpack = require("webpack");
+const CopyWebpackPlugin = require("copy-webpack-plugin");
+const TerserPlugin = require('terser-webpack-plugin');
+
+// const __dirname = (path => path.replace(/^([a-z]\:)/, c => c.toUpperCase()))(process.__dirname());
+
+module.exports = (env) => {
+ const distPath = path.resolve(__dirname, env === "release" ? "." : "../..", "dist");
+ const frameworkPath = path.resolve(__dirname, env === "release" ? "../../framework" : "../..", "dist");
+ return [{
+ name: "App",
+
+ mode: "none", //disable default behavior
+
+ target: "web",
+
+ context: path.resolve(__dirname, "src"),
+
+ entry: {
+ lineOfSightApp: ["./pluginLineOfSight.tsx"]
+ },
+
+ devtool: env === "release" ? false : "source-map",
+
+ resolve: {
+ extensions: [".ts", ".tsx", ".js", ".jsx"]
+ },
+
+ output: {
+ path: distPath,
+ filename: "[name].js",
+ library: "[name]",
+ libraryTarget: "umd2",
+ chunkFilename: "[name].js"
+ },
+ module: {
+ rules: [{
+ test: /\.tsx?$/,
+ exclude: /node_modules/,
+ use: [{
+ loader: "babel-loader"
+ }, {
+ loader: "ts-loader"
+ }]
+ }, {
+ test: /\.jsx?$/,
+ exclude: /node_modules/,
+ use: [{
+ loader: "babel-loader"
+ }]
+ },
+ {
+ test: /\.(png|gif|jpg|svg)$/,
+ use: [{
+ loader: 'url-loader',
+ options: {
+ limit: 10000,
+ name: './icons/[hash].[ext]'
+ }
+ }]
+ },
+ {
+ test: /\.css$/i,
+ use: ["style-loader", "css-loader"],
+ },
+ ]
+ },
+
+ optimization: {
+ noEmitOnErrors: true,
+ namedModules: env !== "release",
+ minimize: env === "release",
+ minimizer: env !== "release" ? [] : [new TerserPlugin({
+ terserOptions: {
+ warnings: false, // false, true, "verbose"
+ compress: {
+ drop_console: true,
+ drop_debugger: true,
+ }
+ }
+ })],
+ },
+
+ plugins: [
+ new webpack.DllReferencePlugin({
+ context: path.resolve(__dirname, "../../framework/src"),
+ manifest: require(path.resolve(frameworkPath, "vendor-manifest.json")),
+ sourceType: "umd2"
+ }),
+ new webpack.DllReferencePlugin({
+ context: path.resolve(__dirname, "../../framework/src"),
+ manifest: require(path.resolve(frameworkPath, "app-manifest.json")),
+ sourceType: "umd2"
+ }),
+ ...(env === "release") ? [
+ new webpack.DefinePlugin({
+ "process.env": {
+ NODE_ENV: "'production'",
+ VERSION: JSON.stringify(require("./package.json").version)
+ }
+ }),
+ ] : [
+ new webpack.DefinePlugin({
+ "process.env": {
+ NODE_ENV: "'development'",
+ VERSION: JSON.stringify(require("./package.json").version)
+ }
+ }),
+ new CopyWebpackPlugin([{
+ from: 'index.html',
+ to: distPath
+ }]),
+ ]
+ ],
+
+ devServer: {
+ public: "http://localhost:3100",
+ contentBase: frameworkPath,
+
+ compress: true,
+ headers: {
+ "Access-Control-Allow-Origin": "*"
+ },
+ host: "0.0.0.0",
+ port: 3100,
+ disableHostCheck: true,
+ historyApiFallback: true,
+ inline: true,
+ hot: false,
+ quiet: false,
+ stats: {
+ colors: true
+ },
+ proxy: {
+ "/yang-schema/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/userdata": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/userdata/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/oauth2/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/database/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/restconf/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/rests/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/topology/": {
+ target: "http://localhost:3002",
+ secure: false
+ },
+ "/sitedoc/": {
+ target: "http://10.20.35.184:3002",
+ secure: false,
+ pathRewrite(pathname) {
+ return pathname.replace(/^\/sitedoc/, '/topology/stadok')
+ }
+ },
+ "/terrain/": {
+ target: "http://10.20.11.163:5200",
+ secure: false,
+ pathRewrite(pathname) {
+ return pathname.replace(/^\/terrain/, '/')
+ }
+ },
+ "/tiles/": {
+ target: "http://tile.openstreetmap.org",
+ secure: false,
+ pathRewrite(pathname) {
+ return pathname.replace(/^\/tiles/, '')
+ }
+ },
+ "/help/": {
+ target: "http://sdnr:8181",
+ secure: false
+ },
+ "/websocket": {
+ target: "http://sdnr:8181",
+ ws: true,
+ changeOrigin: true,
+ secure: false
+ }
+ }
+
+ }
+ }];
+}
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/actions/commonLinkCalculationActions.ts b/sdnr/wt/odlux/apps/linkCalculationApp/src/actions/commonLinkCalculationActions.ts
index 0849058dc..d499ec209 100644
--- a/sdnr/wt/odlux/apps/linkCalculationApp/src/actions/commonLinkCalculationActions.ts
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/actions/commonLinkCalculationActions.ts
@@ -116,60 +116,45 @@ export class UpdateWorstMonthRainAction extends Action {
}
}
-export class UpdateEIRPAction extends Action {
- constructor(public eirpA: number,public eirpB: number) {
+
+export class UpdateAntennaGainAction extends Action {
+ constructor(public antennaGainA: number, public antennaGainB: number) {
super();
}
}
-export class UpdateAntennaGainAction extends Action {
- constructor(public antennaGainList: string[]) {
+export class updateAntennaNameAction extends Action {
+ constructor(public antennaNameA: string, public antennaNameB: string) {
super();
}
}
-export class UpdateAntennaListAction extends Action {
- constructor(public antennaList: string[]) {
+export class UpdateTxPowerAction extends Action {
+ constructor(public txPowerA: string | null, public txPowerB: string | null) {
super();
}
}
-export class UpdateAntennaAction extends Action {
- constructor(public antennaA: string | null, public antennaB : string | null) {
+export class UpdateRxSensitivityAction extends Action {
+ constructor(public rxSensitivityA: string | null, public rxSensitivityB: string | null) {
super();
}
}
-export class UpdateRadioAttributesAction extends Action {
- constructor(public som: number , public eirpA : number, public eirpB : number) {
+export class UpdateWaveguideLossAction extends Action {
+ constructor(public waveguideLossA: number, public waveguideLossB: number) {
super();
}
}
-export class UpdateTxPowerAction extends Action {
- constructor(public txPowerA: string | null , public txPowerB : string | null) {
+
+export class UpdateEIRPAction extends Action {
+ constructor(public eirpA: number, public eirpB: number) {
super();
}
}
-export class UpdateRxSensitivityAction extends Action {
- constructor(public rxSensitivityA: string | null , public rxSensitivityB : string | null) {
+export class UpdateRxPowerAction extends Action {
+ constructor(public rxPowerA: number, public rxPowerB: number) {
super();
}
}
-
-
-export const updateAntennaList = (frequency: number) => async (dispatcher: Dispatch, getState: () => IApplicationStoreState) => {
- let antennaList: string[] = []
- let antennaDiameterList: string[] = []
- let antennaGainList :string[] =[]
- //switch case here frequency = 26? antennaList.push
- switch (frequency) {
- case 7: antennaList.push('ANDREW VHLPX2.5-7W', 'ANDREW VHLPX3-7W', 'ANDREW VHLPX4-7W', 'ANDREW VHLPX6-7W' ), antennaDiameterList.push('0.6','0.9','1.2','1.8'), antennaGainList.push('33.90','35.50','37.30','40.61'); break
- case 11: antennaList.push('ANDREW VHLPX2-11W', 'ANDREW VHLPX3-11W', 'ANDREW VHLPX4-11W'), antennaDiameterList.push('0.6','0.9','1.2'), antennaGainList.push('34.50','38.4','40.70');break
- case 15: antennaList.push('ANDREW VHLPX1-15', 'ANDREW VHLPX2-15', 'ANDREW VHLPX3-15', 'ANDREW VHLPX4-15'), antennaDiameterList.push('0.3','0.6','0.9','1.2'), antennaGainList.push('32.00','36.80','41.11','42.90');break
- case 23: antennaList.push('ANDREW VHLPX1-23', 'ANDREW VHLPX2-23', 'ANDREW VHLPX3-23', 'ANDREW VHLPX4-23'), antennaDiameterList.push('0.3','0.6','0.9','1.2'), antennaGainList.push('35.30','40.21','44.80','46.71');break
- case 26: antennaList.push('ANDREW VHLPX1-26', 'ANDREW VHLPX2-26', 'ANDREW VHLPX3-26'), antennaDiameterList.push('0.3','0.6','0.9'), antennaGainList.push('36.61','40.21','41.21','45.80');break
- case 28: antennaList.push('ANDREW VHLPX1-28', 'ANDREW VHLPX2-28'), antennaDiameterList.push('0.3','0.6'), antennaGainList.push('38.11','42.21');break
- case 38: antennaList.push('ANDREW VHLPX1-38', 'ANDREW VHLPX2-38'), antennaDiameterList.push('0.3','0.6'), antennaGainList.push('40.11','45.21');break
- case 42: antennaList.push('ANDREW VHLPX1-42-XXX/D', 'ANDREW VHLPX2-42-XXX/A'), antennaDiameterList.push('0.3','0.6'), antennaGainList.push('40.80','46.00');break
- case 80: antennaList.push('Radio Waves HPCPE-80', 'Radio Waves HPLP2-80'), antennaDiameterList.push('0.3','0.6'), antennaGainList.push('43.80','50.80');break
- }
- dispatcher(new UpdateAntennaListAction(antennaList))
- dispatcher(new UpdateAntennaGainAction(antennaGainList))
+export class UpdateSomAction extends Action {
+ constructor(public somA: number, public somB:number) {
+ super();
+ }
}
-
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/handlers/linkCalculationAppRootHandler.ts b/sdnr/wt/odlux/apps/linkCalculationApp/src/handlers/linkCalculationAppRootHandler.ts
index edfad052a..01512eb92 100644
--- a/sdnr/wt/odlux/apps/linkCalculationApp/src/handlers/linkCalculationAppRootHandler.ts
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/handlers/linkCalculationAppRootHandler.ts
@@ -21,7 +21,7 @@ import { combineActionHandler } from '../../../../framework/src/flux/middleware'
// ** do not remove **
import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
import { IActionHandler } from '../../../../framework/src/flux/action';;
-import { UpdateLinkIdAction, UpdateFrequencyAction , UpdateLatLonAction, UpdateRainAttAction, UpdateRainValAction, updateHideForm, UpdateFslCalculation, UpdateSiteAction, UpdateDistanceAction, isCalculationServerReachableAction, UpdatePolAction, updateAltitudeAction, UpdateAbsorptionLossAction, UpdateWorstMonthRainAction, UpdateEIRPAction, UpdateAntennaAction, UpdateAntennaListAction, UpdateAntennaGainAction, UpdateTxPowerAction, UpdateRxSensitivityAction} from '../actions/commonLinkCalculationActions';
+import { UpdateLinkIdAction, UpdateFrequencyAction , UpdateLatLonAction, UpdateRainAttAction, UpdateRainValAction, updateHideForm, UpdateFslCalculation, UpdateSiteAction, UpdateDistanceAction, isCalculationServerReachableAction, UpdatePolAction, updateAltitudeAction, UpdateAbsorptionLossAction, UpdateWorstMonthRainAction, UpdateEIRPAction, UpdateAntennaGainAction, UpdateTxPowerAction, UpdateRxSensitivityAction, updateAntennaNameAction, UpdateWaveguideLossAction, UpdateRxPowerAction, UpdateSomAction} from '../actions/commonLinkCalculationActions';
declare module '../../../../framework/src/store/applicationStore' {
interface IApplicationStoreState {
@@ -60,15 +60,18 @@ export type ILinkCalculationAppStateState= {
eirpB: number,
antennaGainA: number,
antennaGainB :number,
- antennaList:string[],
- antennaGainList:string[],
- antennaA: string,
- antennaB:string,
- systemOperatingMargin : number,
+ antennaNameA: string,
+ antennaNameB:string,
+ systemOperatingMarginA : number,
+ systemOperatingMarginB : number,
txPowerA : string,
txPowerB: string,
rxSensitivityA : string,
- rxSensitivityB: string
+ rxSensitivityB: string,
+ waveguideLossA : number,
+ waveguideLossB: number,
+ rxPowerA :number,
+ rxPowerB: number
}
const initialState: ILinkCalculationAppStateState ={
@@ -98,19 +101,20 @@ const initialState: ILinkCalculationAppStateState ={
eirpB: 0,
antennaGainA :0,
antennaGainB :0,
- antennaList:[],
- antennaGainList:[],
- antennaA: '0',
- antennaB:'0',
- systemOperatingMargin : 0,
+ antennaNameA: '',
+ antennaNameB:'',
+ systemOperatingMarginA : 0,
+ systemOperatingMarginB : 0,
txPowerA : '0',
txPowerB: '0',
rxSensitivityA: '0',
- rxSensitivityB: '0'
+ rxSensitivityB: '0',
+ waveguideLossA : 0,
+ waveguideLossB: 0,
+ rxPowerA : 0,
+ rxPowerB: 0
}
-
-
export const LinkCalculationHandler: IActionHandler<ILinkCalculationAppStateState> = (state=initialState, action) => {
if(action instanceof UpdateLinkIdAction){
@@ -156,17 +160,12 @@ export const LinkCalculationHandler: IActionHandler<ILinkCalculationAppStateStat
else if (action instanceof UpdateWorstMonthRainAction){
state = Object.assign({}, state, {month:action.month})
}
- else if (action instanceof UpdateEIRPAction){
- state = Object.assign({}, state, {eirpA:action.eirpA, eirpB:action.eirpB})
- }
+
else if (action instanceof UpdateAntennaGainAction){
- state = Object.assign({}, state, {antennaGainList:action.antennaGainList})
- }
- else if (action instanceof UpdateAntennaListAction){
- state = Object.assign({}, state, {antennaList:action.antennaList})
+ state = Object.assign({}, state, {antennaGainA:action.antennaGainA,antennaGainB:action.antennaGainB})
}
- else if (action instanceof UpdateAntennaAction){
- state = Object.assign({}, state, {antennaA:action.antennaA == null ? state.antennaA : action.antennaA , antennaB: action.antennaB == null? state.antennaB : action.antennaB})
+ else if (action instanceof updateAntennaNameAction){
+ state = Object.assign({}, state, {antennaNameA:action.antennaNameA, antennaNameB: action.antennaNameB})
}
else if (action instanceof UpdateTxPowerAction){
state = Object.assign({}, state, {txPowerA:action.txPowerA == null ? state.txPowerA : action.txPowerA , txPowerB: action.txPowerB == null? state.txPowerB : action.txPowerB})
@@ -174,6 +173,19 @@ export const LinkCalculationHandler: IActionHandler<ILinkCalculationAppStateStat
else if (action instanceof UpdateRxSensitivityAction){
state = Object.assign({}, state, {rxSensitivityA:action.rxSensitivityA == null ? state.rxSensitivityA : action.rxSensitivityA , rxSensitivityB: action.rxSensitivityB == null? state.rxSensitivityB : action.rxSensitivityB})
}
+ else if (action instanceof UpdateWaveguideLossAction){
+ state = Object.assign({}, state, {waveguideLossA:action.waveguideLossA, waveguideLossB: action.waveguideLossB})
+ }
+ else if (action instanceof UpdateEIRPAction){
+ state = Object.assign({}, state, {eirpA:action.eirpA, eirpB:action.eirpB})
+ }
+ else if (action instanceof UpdateRxPowerAction){
+ state = Object.assign({}, state, {rxPowerA:action.rxPowerA, rxPowerB:action.rxPowerB})
+ }
+ else if (action instanceof UpdateSomAction){
+ state = Object.assign({}, state, {systemOperatingMarginA:action.somA , systemOperatingMarginB :action.somB})
+ }
+
return state
}
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/index.html b/sdnr/wt/odlux/apps/linkCalculationApp/src/index.html
index 2023ae365..edcbd2514 100644
--- a/sdnr/wt/odlux/apps/linkCalculationApp/src/index.html
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/index.html
@@ -15,10 +15,11 @@
<script type="text/javascript" src="./config.js"></script>
<script>
// run the application
- require(["app","connectApp", "linkCalculationApp", "networkMapApp"], function (app, connectApp, linkCalculationApp,networkMapApp) {
+ require(["app","connectApp", "linkCalculationApp", "networkMapApp" , "lineOfSightApp"], function (app, connectApp, linkCalculationApp,networkMapApp, lineOfSightApp) {
connectApp.register();
linkCalculationApp.register();
networkMapApp.register();
+ lineOfSightApp.register();
app("./app.tsx").runApplication();
});
</script>
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/pluginLinkCalculation.tsx b/sdnr/wt/odlux/apps/linkCalculationApp/src/pluginLinkCalculation.tsx
index f86b22a5c..a15bf033d 100644
--- a/sdnr/wt/odlux/apps/linkCalculationApp/src/pluginLinkCalculation.tsx
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/pluginLinkCalculation.tsx
@@ -24,11 +24,11 @@ import { withRouter, RouteComponentProps, Route, Switch, Redirect } from 'react-
import { faBookOpen } from '@fortawesome/free-solid-svg-icons'; // select app icon
import applicationManager from '../../../framework/src/services/applicationManager';
-import LinkCalculation from './views/linkCalculationComponent';
+import LinkCalculation from './views/linkCalculationComponent';
import LinkCalculationAppRootHandler from './handlers/linkCalculationAppRootHandler';
import connect, { Connect, IDispatcher } from '../../../framework/src/flux/connect';
import { IApplicationStoreState } from "../../../framework/src/store/applicationStore";
-import { UpdateLinkIdAction, UpdateLatLonAction, updateHideForm, UpdateSiteAction, UpdateDistanceAction, isCalculationServerReachableAction, updateAltitudeAction } from "./actions/commonLinkCalculationActions";
+import { UpdateLinkIdAction, UpdateLatLonAction, updateHideForm, UpdateSiteAction, UpdateDistanceAction, isCalculationServerReachableAction, updateAltitudeAction, updateAntennaNameAction, UpdateAntennaGainAction, UpdateWaveguideLossAction } from "./actions/commonLinkCalculationActions";
let currentLinkId: string | null = null;
@@ -41,23 +41,29 @@ const mapProps = (state: IApplicationStoreState) => ({
const mapDisp = (dispatcher: IDispatcher) => ({
updateLinkId: (mountId: string) => dispatcher.dispatch(new UpdateLinkIdAction(mountId)),
- updateSiteName: (siteNameA?:any, siteNameB?:any)=>{
+ updateSiteName: (siteNameA?: any, siteNameB?: any) => {
dispatcher.dispatch(new UpdateSiteAction(siteNameA, siteNameB))
},
- updateDistance :(distance:number) =>{
+ updateDistance: (distance: number) => {
dispatcher.dispatch(new UpdateDistanceAction(distance))
},
- updateLatLon : (Lat1:number, Lon1:number, Lat2:number, Lon2:number)=> {
+ updateLatLon: (Lat1: number, Lon1: number, Lat2: number, Lon2: number) => {
dispatcher.dispatch(new UpdateLatLonAction(Lat1, Lon1, Lat2, Lon2))
- dispatcher.dispatch(new updateHideForm (true))
+ dispatcher.dispatch(new updateHideForm(true))
},
- updateAltitude : (amslA:number, aglA:number, amslB:number, aglB:number) => {
- dispatcher.dispatch(new updateAltitudeAction(amslA,aglA,amslB,aglB))
+ updateAltitude: (amslA: number, aglA: number, amslB: number, aglB: number) => {
+ dispatcher.dispatch(new updateAltitudeAction(amslA, aglA, amslB, aglB))
+ },
+ updateAntennaName: (antennaNameA: string, antennaNameB: string) => {
+ dispatcher.dispatch(new updateAntennaNameAction(antennaNameA, antennaNameB))
+ },
+ updateAntennaGainAction: (antennaGainA: number, antennaGainB: number) => {
+ dispatcher.dispatch(new UpdateAntennaGainAction(antennaGainA, antennaGainB))
+ },
+ updateWaveguideLossAction: (waveguideLossA: number, waveguideLossB: number) => {
+ dispatcher.dispatch(new UpdateWaveguideLossAction(waveguideLossA, waveguideLossB))
}
- // UpdateConectivity : (reachable:boolean) => {
- // dispatcher.dispatch (new isCalculationServerReachableAction (reachable))
- // }
});
@@ -70,45 +76,68 @@ const LinkCalculationRouteAdapter = connect(mapProps, mapDisp)((props: RouteComp
lastUrl = props.location.pathname;
linkId = getLinkId(lastUrl);
- const data= props.location.search
+ const data = props.location.search
+
-
- if (data !== undefined && data.length>0){
+ if (data !== undefined && data.length > 0) {
-
- const lat1 = data.split('&')[0].split('=')[1]
- const lon1 = data.split('&')[1].split('=')[1]
- const lat2 = data.split('&')[2].split('=')[1]
- const lon2 = data.split('&')[3].split('=')[1]
- const siteNameA = data.split('&')[4].split('=')[1]
- const siteNameB = data.split('&')[5].split('=')[1]
+ const lat1 = data.split('&')[0].split('=')[1]
+ const lon1 = data.split('&')[1].split('=')[1]
+ const lat2 = data.split('&')[2].split('=')[1]
+ const lon2 = data.split('&')[3].split('=')[1]
- const distance = data.split('&')[8].split('=')[1]
+ const siteNameA = data.split('&')[4].split('=')[1]
+ const siteNameB = data.split('&')[5].split('=')[1]
- const amslA = data.split('&')[9].split('=')[1]
- const aglA = data.split('&')[10].split('=')[1]
+ const distance = data.split('&')[8].split('=')[1]
- const amslB = data.split('&')[11].split('=')[1]
- const aglB = data.split('&')[12].split('=')[1]
+ const amslA = data.split('&')[9].split('=')[1]
+ const aglA = data.split('&')[10].split('=')[1]
+ const amslB = data.split('&')[11].split('=')[1]
+ const aglB = data.split('&')[12].split('=')[1]
- props.updateSiteName(String(siteNameA), String(siteNameB))
+ const antennaNameA = data.split('&')[13].split('=')[1].replace("%20", " ")
+ const antennaGainA = data.split('&')[14].split('=')[1]
+ const waveguideLossA = data.split('&')[15].split('=')[1]
+ const antennaNameB = data.split('&')[16].split('=')[1].replace("%20", " ")
+ const antennaGainB = data.split('&')[17].split('=')[1]
+ const waveguideLossB = data.split('&')[18].split('=')[1]
- props.updateDistance(Number(distance))
- props.updateLatLon(Number(lat1),Number(lon1),Number(lat2),Number(lon2))
+ if (siteNameA !== null && siteNameB !== null) {
+ props.updateSiteName(String(siteNameA), String(siteNameB))
+ }
- props.updateAltitude (Number(amslA), Number(aglA), Number(amslB), Number(aglB))
-
+ if (Number(distance) !== null) {
+ props.updateDistance(Number(distance))
+ }
+ if (Number(lat1) >= -90 && Number(lat2) >= -90 && Number(lat1) <= 90 && Number(lat2) <= 90 && Number(lon1) >= -180 && Number(lon2) >= -180 && Number(lon1) <= 180 && Number(lon2) <= 180) {
+ props.updateLatLon(Number(lat1), Number(lon1), Number(lat2), Number(lon2))
+ }
+ if (Number(amslA)> 0 && Number(amslB)> 0) {
+ if (Number(aglA)>= Number(amslA) && Number(aglB)>= Number(amslB)) {
+ props.updateAltitude(Number(amslA), Number(aglA), Number(amslB), Number(aglB))
+ }
+ }
+ if (antennaNameA && antennaNameB.length) {
+ props.updateAntennaName(String(antennaNameA), String(antennaNameB))
+ }
+ if (Number(antennaGainA) > 0 && Number(antennaGainA) > 0) {
+ props.updateAntennaGainAction(Number(antennaGainA), Number(antennaGainB))
+ }
+ if(Number(waveguideLossA) !== null, Number(waveguideLossB) !== null){
+ props.updateWaveguideLossAction(Number(waveguideLossA),Number(waveguideLossB) )
+ }
}
-
+
if (currentLinkId !== linkId) { // new element is loaded
currentLinkId = linkId;
props.updateLinkId(currentLinkId);
- }
+ }
}, []);
// called when component gets updated
@@ -126,7 +155,7 @@ const LinkCalculationRouteAdapter = connect(mapProps, mapDisp)((props: RouteComp
const getLinkId = (lastUrl: string) => {
let index = lastUrl.lastIndexOf("linkCalculation/");
if (index >= 0) {
- linkId = lastUrl.substr(index+16);
+ linkId = lastUrl.substr(index + 16);
} else {
linkId = "";
}
@@ -134,7 +163,7 @@ const LinkCalculationRouteAdapter = connect(mapProps, mapDisp)((props: RouteComp
return linkId;
}
-
+
return (
<LinkCalculation />
);
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/views/linkCalculationComponent.tsx b/sdnr/wt/odlux/apps/linkCalculationApp/src/views/linkCalculationComponent.tsx
index 063926269..e3eaa6ba0 100644
--- a/sdnr/wt/odlux/apps/linkCalculationApp/src/views/linkCalculationComponent.tsx
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/views/linkCalculationComponent.tsx
@@ -24,7 +24,7 @@ import { TextField, Tabs, Tab, Typography, AppBar, Button, Tooltip, Checkbox, Ta
import './Style.scss'
import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore";
-import { UpdateFrequencyAction, UpdateLatLonAction, UpdateRainAttAction, UpdateRainValAction, UpdateFslCalculation, isCalculationServerReachableAction, UpdatePolAction, UpdateDistanceAction, updateAltitudeAction, UpdateAbsorptionLossAction, UpdateWorstMonthRainAction, updateAntennaList, UpdateAntennaAction, UpdateRadioAttributesAction, UpdateTxPowerAction, UpdateRxSensitivityAction } from "../actions/commonLinkCalculationActions";
+import { UpdateFrequencyAction, UpdateLatLonAction, UpdateRainAttAction, UpdateRainValAction, UpdateFslCalculation, isCalculationServerReachableAction, UpdatePolAction, UpdateDistanceAction, updateAltitudeAction, UpdateAbsorptionLossAction, UpdateWorstMonthRainAction, UpdateTxPowerAction, UpdateRxSensitivityAction, UpdateEIRPAction, UpdateRxPowerAction, UpdateSomAction } from "../actions/commonLinkCalculationActions";
import { faPlaneArrival, faAlignCenter } from "@fortawesome/free-solid-svg-icons";
import ConnectionInfo from '../components/connectionInfo'
import { red } from "@material-ui/core/colors";
@@ -55,15 +55,22 @@ const mapProps = (state: IApplicationStoreState) => ({
absorptionOxygen: state.linkCalculation.calculations.absorptionOxygen,
absorptionWater: state.linkCalculation.calculations.absorptionWater,
month: state.linkCalculation.calculations.month,
- eirpSiteA: state.linkCalculation.calculations.eirpA,
- eirpSiteB: state.linkCalculation.calculations.eirpB,
+ eirpA: state.linkCalculation.calculations.eirpA,
+ eirpB: state.linkCalculation.calculations.eirpB,
antennaGainA: state.linkCalculation.calculations.antennaGainA,
antennaGainB: state.linkCalculation.calculations.antennaGainB,
- antennaList: state.linkCalculation.calculations.antennaList,
- antennaGainList: state.linkCalculation.calculations.antennaGainList,
- antennaA: state.linkCalculation.calculations.antennaA,
- antennaB: state.linkCalculation.calculations.antennaB,
- systemOperatingMargin : state.linkCalculation.calculations.systemOperatingMargin
+ antennaNameA: state.linkCalculation.calculations.antennaNameA,
+ antennaNameB: state.linkCalculation.calculations.antennaNameB,
+ systemOperatingMarginA: state.linkCalculation.calculations.systemOperatingMarginA,
+ systemOperatingMarginB: state.linkCalculation.calculations.systemOperatingMarginB,
+ waveguideLossA: state.linkCalculation.calculations.waveguideLossA,
+ waveguideLossB: state.linkCalculation.calculations.waveguideLossB,
+ rxPowerA: state.linkCalculation.calculations.rxPowerA,
+ rxPowerB: state.linkCalculation.calculations.rxPowerB,
+ txPowerA: state.linkCalculation.calculations.txPowerA,
+ txPowerB: state.linkCalculation.calculations.txPowerB,
+ rxSensitivityA: state.linkCalculation.calculations.rxSensitivityA,
+ rxSensitivityB: state.linkCalculation.calculations.rxSensitivityB
});
@@ -74,7 +81,6 @@ const mapDispatch = (dispatcher: IDispatcher) => ({
updateFrequency: (frequency: number) => {
dispatcher.dispatch(new UpdateFrequencyAction(frequency))
- dispatcher.dispatch(updateAntennaList(frequency))
},
updateLatLon: (Lat1: number, Lon1: number, Lat2: number, Lon2: number) => {
dispatcher.dispatch(new UpdateLatLonAction(Lat1, Lon1, Lat2, Lon2))
@@ -114,16 +120,20 @@ const mapDispatch = (dispatcher: IDispatcher) => ({
UpdateWorstMonthRain: (month: string) => {
dispatcher.dispatch(new UpdateWorstMonthRainAction(month))
},
- UpdateAntenas: (antennaA: string | null, antennaB: string | null) => {
- dispatcher.dispatch(new UpdateAntennaAction(antennaA, antennaB))
+ UpdateEIRP: (eirpA: number, eirpB: number) => {
+ dispatcher.dispatch(new UpdateEIRPAction(eirpA, eirpB))
},
- UpdateRadioAttributes :(som: number, eirpA: number, eirpB: number)=>{
- dispatcher.dispatch(new UpdateRadioAttributesAction(som,eirpA, eirpB))
+ UpdateRxPower: (rxPowerA: number, rxPowerB: number) => {
+ dispatcher.dispatch(new UpdateRxPowerAction(rxPowerA, rxPowerB))
},
- UpdateTxPower :(txPowerA: string | null, txPowerB: string | null)=>{
+ UpdateSom: (somA: number, somB: number) => {
+ dispatcher.dispatch(new UpdateSomAction(somA, somB))
+ },
+
+ UpdateTxPower: (txPowerA: string | null, txPowerB: string | null) => {
dispatcher.dispatch(new UpdateTxPowerAction(txPowerA, txPowerB))
- },
- UpdateRxSensitivity :(rxSensitivityA : string | null, rxSensitivityB : string | null)=>{
+ },
+ UpdateRxSensitivity: (rxSensitivityA: string | null, rxSensitivityB: string | null) => {
dispatcher.dispatch(new UpdateRxSensitivityAction(rxSensitivityA, rxSensitivityB))
}
});
@@ -145,6 +155,7 @@ interface initialState {
attenuationMethodError: string,
worstmonth: boolean,
showWM: string,
+ rainMethodErrorState: string
}
class LinkCalculation extends React.Component<linkCalculationProps, initialState> {
@@ -164,6 +175,7 @@ class LinkCalculation extends React.Component<linkCalculationProps, initialState
antennaTypeError: '',
worstmonth: false,
showWM: '',
+ rainMethodErrorState: '0'
};
}
@@ -246,10 +258,10 @@ class LinkCalculation extends React.Component<linkCalculationProps, initialState
}
}
- linkBudget = (antennaA: string, antennaB: string, transmissionPowerA: number, transmissionPowerB: number) => {
- fetch(BASE_URL + '/linkbudget/' + antennaA + '/' + antennaB + '/' + transmissionPowerA + '/' + transmissionPowerB)
- .then(res=>res.json())
- .then(result => {this.props.UpdateRadioAttributes(result.systemOperatingMargin, result.eirpA, result.eirpB)})
+ linkBudget = (lat1: number, lon1: number, lat2: number, lon2: number, distance: number, frequency: number, absorptionMethod: string, polarization: string, antennaGainA: number, antennaGainB: number, waveguideLossA: number, waveguideLossB: number, transmissionPowerA: number, transmissionPowerB: number, rxSensitivityA: number, rxSensitivityB: number) => {
+ fetch(BASE_URL + '/linkbudget/' + lat1 + ',' + lon1 + ',' + lat2 + ',' + lon2 + '/' + distance + '/' + frequency + '/' + absorptionMethod + '/' + polarization.toUpperCase() + '/' + antennaGainA + '/' + antennaGainB + '/' + waveguideLossA + '/' + waveguideLossB + '/' + transmissionPowerA + '/' + transmissionPowerB + '/' + rxSensitivityA + '/' + rxSensitivityB)
+ .then(res => res.json())
+ .then(result => { this.props.UpdateEIRP(result.eirpA, result.eirpB); this.props.UpdateRxPower(result.receivedPowerA, result.receivedPowerB); this.props.UpdateSom(result.systemOperatingMarginA, result.systemOperatingMarginA) })
}
formValid = () => {
@@ -260,7 +272,10 @@ class LinkCalculation extends React.Component<linkCalculationProps, initialState
this.props.lon2 === 0 ? this.setState({ longitude2Error: 'Enter a number between -180 to 180' }) : null
this.props.frequency === 0 ? this.setState({ frequencyError: 'Select a frequency' }) : this.setState({ frequencyError: '' })
- this.state.rainMethodDisplay === null && this.props.rainVal === 0 ? this.setState({ rainMethodError: 'Select the rain method' }) : this.setState({ rainMethodError: '' })
+ // this.state.rainMethodDisplay === null && this.props.rainVal === 0 ? this.setState({ rainMethodError: 'Select the rain method' }) : this.setState({ rainMethodError: '' })
+
+ this.state.rainMethodErrorState === '0' ? this.setState({ rainMethodError: 'Select the rain method' }) : this.setState({ rainMethodError: '' })
+
this.state.absorptionMethod === '0' ? this.setState({ attenuationMethodError: 'Select the attenuation method' }) : this.setState({ attenuationMethodError: '' })
console.log(this.state);
console.log(this.props.lat1 !== 0 && this.props.lat2 !== 0 && this.props.lon1 !== 0 && this.props.lon2 !== 0 && this.props.frequency !== 0 && this.state.rainMethodError === '' && this.state.attenuationMethodError === '');
@@ -282,21 +297,18 @@ class LinkCalculation extends React.Component<linkCalculationProps, initialState
this.setState({ showWM: ' ' })
this.props.UpdateWorstMonthRain('')
this.AbsorptionAtt(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2, this.props.distance, this.props.frequency, this.state.worstmonth, this.state.absorptionMethod)
+ this.linkBudget(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2, this.props.distance, this.props.frequency, this.state.absorptionMethod, this.props.polarization!, this.props.antennaGainA, this.props.antennaGainB, this.props.waveguideLossA, this.props.waveguideLossB, Number(this.props.txPowerA), Number(this.props.txPowerB), Number(this.props.rxSensitivityA), Number(this.props.rxSensitivityB))
if (this.state.rainMethodDisplay === true) {
this.manualRain(this.props.rainVal, this.props.frequency, this.props.distance, this.props.polarization!);
}
else {
- // this.updateRainValue(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2, this.state.worstmonth)
this.rainAttCal(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2, this.props.frequency, this.props.distance, this.props.polarization!, this.state.worstmonth);
}
}
else {
this.AbsorptionAtt(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2, this.props.distance, this.props.frequency, this.state.worstmonth, this.state.absorptionMethod)
-
- // this.updateRainValue(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2, this.state.worstmonth)
-
this.rainAttCal(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2, this.props.frequency, this.props.distance, this.props.polarization!, this.state.worstmonth);
}
}
@@ -432,7 +444,7 @@ class LinkCalculation extends React.Component<linkCalculationProps, initialState
</div>
<div>
<div style={{ marginTop: 5 }}>Frequency</div>
- <div style={{ marginTop: 5 }}> {<select aria-label="select-frequency-in-ghz" className={this.state.frequencyError.length > 0 ? 'error' : 'input'} onChange={(e) => { this.props.updateFrequency(Number(e.target.value)); e.target.value === '0' ? this.setState({ frequencyError: 'select a frequency' }) : this.setState({ frequencyError: '' }); this.props.UpdateAntenas('0', '0') }}>
+ <div style={{ marginTop: 5 }}> {<select aria-label="select-frequency-in-ghz" className={this.state.frequencyError.length > 0 ? 'error' : 'input'} onChange={(e) => { this.props.updateFrequency(Number(e.target.value)); e.target.value === '0' ? this.setState({ frequencyError: 'select a frequency' }) : this.setState({ frequencyError: '' }) }}>
<option value='0' aria-label="none-value" >Select Freq</option>
<option value='7' aria-label="7" >7 GHz</option>
@@ -452,7 +464,7 @@ class LinkCalculation extends React.Component<linkCalculationProps, initialState
</div>
<div>
<div>Rain Model</div>
- <div> {<select aria-label="select-rain-method" className={this.state.rainMethodError.length > 0 ? 'error' : 'input'} onChange={(e) => { e.target.value === 'itu' ? this.setState({ rainMethodDisplay: false }) : this.setState({ rainMethodDisplay: true }); e.target.value === '0' ? this.setState({ rainMethodError: 'select a Rain model' }) : this.setState({ rainMethodError: '' }) }}>
+ <div> {<select aria-label="select-rain-method" className={this.state.rainMethodError.length > 0 ? 'error' : 'input'} onChange={(e) => {if (e.target.value !== '') { this.setState({ rainMethodErrorState: e.target.value, rainMethodError: '' }) }; e.target.value === 'itu' ? this.setState({ rainMethodDisplay: false }) : this.setState({ rainMethodDisplay: true }) }}>
<option value='0' aria-label="none-value" >Select Rain Method</option>
<option value='itu' aria-label="itur8377">ITU-R P.837-7</option>
<option value='manual' aria-label="manual-entry">Specific Rain</option>
@@ -471,7 +483,7 @@ class LinkCalculation extends React.Component<linkCalculationProps, initialState
</div>
<div>
<div>Absorption Model</div>
- <div> {<select aria-label="select-absorption-method" className={this.state.attenuationMethodError.length > 0 ? 'error' : 'input'} onChange={(e) => { if (e.target.value !== '') { this.setState({ absorptionMethod: e.target.value }); this.setState({ attenuationMethodError: '' }) } }}>
+ <div> {<select aria-label="select-absorption-method" className={this.state.attenuationMethodError.length > 0 ? 'error' : 'input'} onChange={(e) => { if (e.target.value !== '') { this.setState({ absorptionMethod: e.target.value, attenuationMethodError: '' }) } }}>
<option value='0' aria-label="none-value" >Select Absorption Method</option>
<option value='ITURP67612' aria-label="iturp67612" >ITU-R P.676-12</option>
<option value='ITURP67611' aria-label="iturp67611" >ITU-R P.676-11</option>
@@ -489,14 +501,15 @@ class LinkCalculation extends React.Component<linkCalculationProps, initialState
</div>
<div>
<div>System Operating Margin</div>
- <div aria-label="system-operating-margin">{this.props.systemOperatingMargin} dB</div>
+ <div aria-label="system-operating-margin">{this.props.systemOperatingMarginA.toFixed(3)} dB</div>
+ <div aria-label="system-operating-margin">{this.props.systemOperatingMarginB.toFixed(3)} dB</div>
</div>
<div>
- <div>Radio Transmitted Power</div>
- <div> {<form><input aria-label="site-a-transmitted-power" type="number" style={{ width: 70, height: 15, fontSize: 14 }} onChange={(e) => {if (e.target.value !== '') this.props.UpdateTxPower(e.target.value,null) }}
+ <div>Radio Transmitted Power</div>
+ <div> {<form><input aria-label="site-a-transmitted-power" type="number" style={{ width: 70, height: 15, fontSize: 14 }} onChange={(e) => { if (e.target.value !== '') this.props.UpdateTxPower(e.target.value, null) }}
>
</input> dBm </form>} </div>
- <div> {<form><input aria-label="site-b-transmitted-power" type="number" style={{ width: 70, height: 15, fontSize: 14 }} onChange={(e) => { if (e.target.value !== '') this.props.UpdateTxPower(null,e.target.value) }}
+ <div> {<form><input aria-label="site-b-transmitted-power" type="number" style={{ width: 70, height: 15, fontSize: 14 }} onChange={(e) => { if (e.target.value !== '') this.props.UpdateTxPower(null, e.target.value) }}
>
</input> dBm </form>} </div>
</div>
@@ -509,41 +522,43 @@ class LinkCalculation extends React.Component<linkCalculationProps, initialState
>
</input> dBm </form>} </div>
</div>
+ <div>
+ <div>Rx power</div>
+ <div aria-label="site-a-effective-isotropic-radiated-power">{this.props.rxPowerA.toFixed(3)} dBm</div>
+ <div aria-label="site-b-effective-isotropic-radiated-power">{this.props.rxPowerB.toFixed(3)} dBm</div>
+ </div>
</div>
<div className='antennaContainer'>
<div>
<div></div>
<div className='antennaFont'>Antenna Settings</div>
</div>
+
<div>
<div>Antenna</div>
+ <div aria-label="site-a-amsl">{this.props.antennaNameA} </div>
+ <div aria-label="site-b-amsl">{this.props.antennaNameB}</div>
+ </div>
- <div> {<select aria-label="site-a-select-antenna" value={this.props.antennaA} style={{ width: 160, height: 22, fontSize: 13 }} className={this.state.antennaTypeError.length > 0 ? 'error' : 'input'} onChange={(e) => { if (e.target.value !== '') { this.props.UpdateAntenas(e.target.value, null); this.setState({ antennaTypeError: '' }) } }}>
- <option value='0' aria-label="none-value" >Select Antenna</option>
- {this.props.antennaList.map(antenna => <option value={antenna}>{antenna}</option>)}
-
- </select>} <div style={{ fontSize: 12, color: 'red' }}>{this.state.antennaTypeError}</div>
- </div>
- <div> {<select aria-label="site-b-select-antenna" value={this.props.antennaB} style={{ width: 160, height: 22, fontSize: 13 }} className={this.state.antennaTypeError.length > 0 ? 'error' : 'input'} onChange={(e) => { if (e.target.value !== '') { this.props.UpdateAntenas(null, e.target.value); this.setState({ antennaTypeError: '' }) } }}>
- <option value='0' aria-label="none-value" >Select Antenna</option>
- {this.props.antennaList.map(antenna => <option value={antenna}>{antenna}</option>)}
- </select>} <div style={{ fontSize: 12, color: 'red' }}>{this.state.antennaTypeError}</div>
- </div>
- </div>
<div>
<div>EIRP</div>
- <div aria-label="site-a-effective-isotropic-radiated-power">{this.props.eirpSiteA} dBm</div>
- <div aria-label="site-b-effective-isotropic-radiated-power">{this.props.eirpSiteB} dBm</div>
+ <div aria-label="site-a-effective-isotropic-radiated-power">{this.props.eirpA.toFixed(3)} dBm</div>
+ <div aria-label="site-b-effective-isotropic-radiated-power">{this.props.eirpB.toFixed(3)} dBm</div>
</div>
-
+
<div>
<div>Gain</div>
- <div aria-label="site-a-antenna-gain" > {this.props.antennaGainList[this.props.antennaList.indexOf(this.props.antennaA)]} dBi</div>
- <div aria-label="site-b-antenna-gain">{this.props.antennaGainList[this.props.antennaList.indexOf(this.props.antennaB)]} dBi</div>
-
+ <div aria-label="site-a-antenna-gain" > {this.props.antennaGainA} dBi</div>
+ <div aria-label="site-b-antenna-gain">{this.props.antennaGainB} dBi</div>
</div>
<div>
+ <div>Waveguide Loss</div>
+ <div aria-label="site-a-waveguide-loss" > {this.props.waveguideLossA} dB</div>
+ <div aria-label="site-b-waveguide-loss">{this.props.waveguideLossB} dB</div>
+ </div>
+
+ <div>
<div></div>
<div>{<button aria-label="calculate-button" style={{ color: '#222', fontFamily: 'Arial', boxAlign: 'center', display: 'inline-block', insetInlineStart: '20', alignSelf: 'center' }}
onClick={(e) => this.buttonHandler()} >Calculate</button>} </div>
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/webpack.config.js b/sdnr/wt/odlux/apps/linkCalculationApp/webpack.config.js
index 515c5826b..55d98b4d7 100644
--- a/sdnr/wt/odlux/apps/linkCalculationApp/webpack.config.js
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/webpack.config.js
@@ -165,6 +165,20 @@ module.exports = (env) => {
ws: true,
changeOrigin: true,
secure: false
+ },
+ "/terrain": {
+ target: "http://10.20.11.163:5200",
+ secure: false,
+ pathRewrite(pathname) {
+ return pathname.replace(/^\/terrain/, '')
+ }
+ },
+ "/terrain/": {
+ target: "http://10.20.11.163:5200",
+ secure: false,
+ pathRewrite(pathname) {
+ return pathname.replace(/^\/terrain/, '/')
+ }
}
}
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/ltpSelection.tsx b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/ltpSelection.tsx
index 61b781384..b6c14a9ce 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/ltpSelection.tsx
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/ltpSelection.tsx
@@ -34,7 +34,7 @@ const useStyles = makeStyles(theme => ({
border: "1px solid #ced4da",
fontSize: 16,
width: "auto",
- padding: "5px 26px 5px 12px",
+ padding: "5px 5px 5px 5px",
transition: theme.transitions.create(["border-color", "box-shadow"]),
},
center: {
diff --git a/sdnr/wt/odlux/framework/package.json b/sdnr/wt/odlux/framework/package.json
index da81a5399..8fd027f74 100644
--- a/sdnr/wt/odlux/framework/package.json
+++ b/sdnr/wt/odlux/framework/package.json
@@ -24,7 +24,7 @@
"author": "Matthias Fischer",
"license": "Apache-2.0",
"peerDependencies": {
- "@types/node": "12.0.0",
+ "@types/node": "^12.0.0",
"@types/react": "17.0.3",
"@types/react-dom": "17.0.2",
"@types/react-router-dom": "5.1.7",
diff --git a/sdnr/wt/odlux/framework/pom.xml b/sdnr/wt/odlux/framework/pom.xml
index 0e7baef79..88f6746ab 100644
--- a/sdnr/wt/odlux/framework/pom.xml
+++ b/sdnr/wt/odlux/framework/pom.xml
@@ -46,7 +46,7 @@
<properties>
<buildtime>${maven.build.timestamp}</buildtime>
<distversion>ONAP Frankfurt (Neon, mdsal ${odl.mdsal.version})</distversion>
- <buildno>115.f8b3b3c(21/07/30)</buildno>
+ <buildno>116.8c2f6b7(21/08/05)</buildno>
<odlux.version>ONAP SDN-R | ONF Wireless for ${distversion} - Build: ${buildtime} ${buildno} ${project.version}</odlux.version>
</properties>
diff --git a/sdnr/wt/odlux/framework/src/views/about.tsx b/sdnr/wt/odlux/framework/src/views/about.tsx
index 174444f70..400ee35bb 100644
--- a/sdnr/wt/odlux/framework/src/views/about.tsx
+++ b/sdnr/wt/odlux/framework/src/views/about.tsx
@@ -46,7 +46,7 @@ type odluxVersion= {version:string,build:string, framework: string,
permanceHistoryApp: string
}};
-type topologyVersion = {version: string};
+type topologyVersion = {version: string, buildTimestamp: string};
class AboutComponent extends React.Component<any, AboutState> {
textarea: React.RefObject<HTMLTextAreaElement>;
@@ -91,7 +91,9 @@ class AboutComponent extends React.Component<any, AboutState> {
}
else
{
- return `| | |\n| --- | --- |\n| Version | ${data.version} |\n`
+ const topologyInfo = `| | |\n| --- | --- |\n| Version | ${data.version} |\n` +
+ `| Build timestamp | ${data.buildTimestamp} |\n`;
+ return topologyInfo;
}
}
diff --git a/sdnr/wt/odlux/installer/pom.xml b/sdnr/wt/odlux/installer/pom.xml
index 19cdba08c..98609e814 100644
--- a/sdnr/wt/odlux/installer/pom.xml
+++ b/sdnr/wt/odlux/installer/pom.xml
@@ -20,7 +20,8 @@
~
-->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
@@ -171,6 +172,14 @@
<type>jar</type>
<overWrite>false</overWrite>
</artifactItem>
+ <!-- line of sight app-->
+ <artifactItem>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sdnr-wt-odlux-app-lineOfSightApp</artifactId>
+ <version>${project.version}</version>
+ <type>jar</type>
+ <overWrite>false</overWrite>
+ </artifactItem>
<!-- inventoryApp -->
<artifactItem>
<groupId>${project.groupId}</groupId>
diff --git a/sdnr/wt/odlux/odlux.properties b/sdnr/wt/odlux/odlux.properties
index 81d2352ba..b47f852e0 100644
--- a/sdnr/wt/odlux/odlux.properties
+++ b/sdnr/wt/odlux/odlux.properties
@@ -1,12 +1,13 @@
-odlux.framework.buildno=112.fc75f5b(21/07/21)
+odlux.framework.buildno=116.8c2f6b7(21/08/05)
odlux.apps.configurationApp.buildno=109.dbfed60(21/06/23)
-odlux.apps.connectApp.buildno=114.1220e03(21/07/30)
+odlux.apps.connectApp.buildno=116.8c2f6b7(21/08/05)
odlux.apps.eventLogApp.buildno=108.a60ec28(21/06/11)
odlux.apps.faultApp.buildno=114.1220e03(21/07/30)
odlux.apps.helpApp.buildno=108.a60ec28(21/06/11)
odlux.apps.inventoryApp.buildno=108.a60ec28(21/06/11)
-odlux.apps.linkCalculationApp.buildno=111.b9067b6(21/07/16)
+odlux.apps.linkCalculationApp.buildno=116.8c2f6b7(21/08/05)
odlux.apps.maintenanceApp.buildno=108.a60ec28(21/06/11)
odlux.apps.mediatorApp.buildno=108.a60ec28(21/06/11)
odlux.apps.networkMapApp.buildno=115.f8b3b3c(21/07/30)
+odlux.apps.lineOfSightApp.buildno=116.8c2f6b7(21/08/05)
odlux.apps.permanceHistoryApp.buildno=81.1c38886(20/12/04)
diff --git a/sdnr/wt/odlux/package.json b/sdnr/wt/odlux/package.json
index 851ebaf00..a8c2d76e0 100644
--- a/sdnr/wt/odlux/package.json
+++ b/sdnr/wt/odlux/package.json
@@ -22,7 +22,7 @@
"@types/glob-to-regexp": "0.4.0",
"@types/jquery": "3.3.10",
"@types/jsonwebtoken": "7.2.8",
- "@types/node": "12.0.0",
+ "@types/node": "^12.0.0",
"@types/react": "17.0.3",
"@types/react-dom": "17.0.2",
"@types/react-router-dom": "5.1.7",
diff --git a/sdnr/wt/odlux/pom.xml b/sdnr/wt/odlux/pom.xml
index 0c1f14934..03c1e9431 100644
--- a/sdnr/wt/odlux/pom.xml
+++ b/sdnr/wt/odlux/pom.xml
@@ -54,6 +54,7 @@
<module>apps/configurationApp</module>
<module>apps/networkMapApp</module>
<module>apps/linkCalculationApp</module>
+ <module>apps/lineOfSightApp</module>
<module>apps/app-feature</module>
<module>apps/app-installer</module>
<module>installer</module>
diff --git a/sdnr/wt/odlux/yarn.lock b/sdnr/wt/odlux/yarn.lock
index f94f49c80..4fb704090 100644
--- a/sdnr/wt/odlux/yarn.lock
+++ b/sdnr/wt/odlux/yarn.lock
@@ -1765,6 +1765,216 @@
resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.6.tgz#dbe8a666156d556ed018e15a4c65f08937c3f628"
integrity sha512-XHcYvVdbtAxVstjKxuULYqYaWIzHR15yr1pZj4fnGChuBVJlIAp9StJna0ZJNSgxPh4Nac2FL4JM3M11Tm6fqQ==
+"@types/d3-array@^2":
+ version "2.12.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-2.12.3.tgz#8d16d51fb04ad5a5a8ebe14eb8263a579f1efdd1"
+ integrity sha512-hN879HLPTVqZV3FQEXy7ptt083UXwguNbnxdTGzVW4y4KjX5uyNKljrQixZcSJfLyFirbpUokxpXtvR+N5+KIg==
+
+"@types/d3-axis@^2":
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-axis/-/d3-axis-2.1.3.tgz#348cca877f6643030aa8c866d08ccae06821a0e2"
+ integrity sha512-QjXjwZ0xzyrW2ndkmkb09ErgWDEYtbLBKGui73QLMFm3woqWpxptfD5Y7vqQdybMcu7WEbjZ5q+w2w5+uh2IjA==
+ dependencies:
+ "@types/d3-selection" "^2"
+
+"@types/d3-brush@^2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-brush/-/d3-brush-2.1.2.tgz#c75890d1ccaef24fba1811daae3f896c1806418b"
+ integrity sha512-DnZmjdK1ycX1CMiW9r5E3xSf1tL+bp3yob1ON8bf0xB0/odfmGXeYOTafU+2SmU1F0/dvcqaO4SMjw62onOu6A==
+ dependencies:
+ "@types/d3-selection" "^2"
+
+"@types/d3-chord@^2":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-chord/-/d3-chord-2.0.3.tgz#3009b792b754da964d893b4269d1fe7757f21370"
+ integrity sha512-koIqSNQLPRQPXt7c55hgRF6Lr9Ps72r1+Biv55jdYR+SHJ463MsB2lp4ktzttFNmrQw/9yWthf/OmSUj5dNXKw==
+
+"@types/d3-color@^2":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-2.0.3.tgz#8bc4589073c80e33d126345542f588056511fe82"
+ integrity sha512-+0EtEjBfKEDtH9Rk3u3kLOUXM5F+iZK+WvASPb0MhIZl8J8NUvGeZRwKCXl+P3HkYx5TdU4YtcibpqHkSR9n7w==
+
+"@types/d3-contour@^2":
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/@types/d3-contour/-/d3-contour-2.0.4.tgz#2fc5aa8949c1a1d12d183633603923025e3d14fd"
+ integrity sha512-WMac1xV/mXAgkgr5dUvzsBV5OrgNZDBDpJk9s3v2SadTqGgDRirKABb2Ek2H1pFlYVH4Oly9XJGnuzxKDduqWA==
+ dependencies:
+ "@types/d3-array" "^2"
+ "@types/geojson" "*"
+
+"@types/d3-delaunay@^5":
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-delaunay/-/d3-delaunay-5.3.1.tgz#47ae03af6b78cb3aa39d3d3c42ca71daca488aef"
+ integrity sha512-F6itHi2DxdatHil1rJ2yEFUNhejj8+0Acd55LZ6Ggwbdoks0+DxVY2cawNj16sjCBiWvubVlh6eBMVsYRNGLew==
+
+"@types/d3-dispatch@^2":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-dispatch/-/d3-dispatch-2.0.1.tgz#d7dc50f9b679996ccf70f3c79dbbf99505a93107"
+ integrity sha512-eT2K8uG3rXkmRiCpPn0rNrekuSLdBfV83vbTvfZliA5K7dbeaqWS/CBHtJ9SQoF8aDTsWSY4A0RU67U/HcKdJQ==
+
+"@types/d3-drag@^2":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-drag/-/d3-drag-2.0.2.tgz#ed538d24456c839967a9ac7aab5e1b63b28bac7f"
+ integrity sha512-m9USoFaTgVw2mmE7vLjWTApT9dMxMlql/dl3Gj503x+1a2n6K455iDWydqy2dfCpkUBCoF82yRGDgcSk9FUEyQ==
+ dependencies:
+ "@types/d3-selection" "^2"
+
+"@types/d3-dsv@^2":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-dsv/-/d3-dsv-2.0.2.tgz#e10fa57576b50ded27e261db9984b9a92efec2f3"
+ integrity sha512-T4aL2ZzaILkLGKbxssipYVRs8334PSR9FQzTGftZbc3jIPGkiXXS7qUCh8/q8UWFzxBZQ92dvR0v7+AM9wL2PA==
+
+"@types/d3-ease@^2":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-2.0.1.tgz#be03d29980ed7359be1d5b93ff666f95ddcbcf48"
+ integrity sha512-Af1ftZXv82ktPCk1+Vxe7f+VSfxDsQ1mwwakDl17+UzI/ii3vsDIAzaBDDSEQd2Cg9BYPTSx8wXH8rJNDuSjeg==
+
+"@types/d3-fetch@^2":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-fetch/-/d3-fetch-2.0.2.tgz#628c65d14b3a0d02fe1b9c2f3098b81a47e370bc"
+ integrity sha512-sllsCSWrNdSvzOJWN5RnxkmtvW9pCttONGajSxHX9FUQ9kOkGE391xlz6VDBdZxLnpwjp3I+mipbwsaCjq4m5A==
+ dependencies:
+ "@types/d3-dsv" "^2"
+
+"@types/d3-force@^2":
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-force/-/d3-force-2.1.3.tgz#7b0d9ff608e394e6675cce5163eda8368fba7a07"
+ integrity sha512-b/1KrS7hESsMXZ3dOh5KrWPoDcQQbQKey344HO7F3o0tEcVzWHIgp1UMfHv8MLcysfHsRSPGpO7dRyLOVhMQnw==
+
+"@types/d3-format@^2":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-format/-/d3-format-2.0.2.tgz#97b2ac314430ae9f7768cc9efba8b23b63af82ef"
+ integrity sha512-OhQPuTeeMhD9A0Ksqo4q1S9Z1Q57O/t4tTPBxBQxRB4IERnxeoEYLPe72fA/GYpPSUrfKZVOgLHidkxwbzLdJA==
+
+"@types/d3-geo@^2":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-geo/-/d3-geo-2.0.3.tgz#4af0f33c9e796aad6c3fc0dd8cadda9886d1fea9"
+ integrity sha512-kFwLEMXq1mGJ2Eho7KrOUYvLcc2YTDeKj+kTFt87JlEbRQ0rgo8ZENNb5vTYmZrJ2xL/vVM5M7yqVZGOPH2JFg==
+ dependencies:
+ "@types/geojson" "*"
+
+"@types/d3-hierarchy@^2":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-2.0.2.tgz#afd09d509c36e8cd4907333556f8b591f23589e9"
+ integrity sha512-6PlBRwbjUPPt0ZFq/HTUyOAdOF3p73EUYots74lHMUyAVtdFSOS/hAeNXtEIM9i7qRDntuIblXxHGUMb9MuNRA==
+
+"@types/d3-interpolate@^2":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-2.0.2.tgz#78eddf7278b19e48e8652603045528d46897aba0"
+ integrity sha512-lElyqlUfIPyWG/cD475vl6msPL4aMU7eJvx1//Q177L8mdXoVPFl1djIESF2FKnc0NyaHvQlJpWwKJYwAhUoCw==
+ dependencies:
+ "@types/d3-color" "^2"
+
+"@types/d3-path@^2":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-2.0.1.tgz#ca03dfa8b94d8add97ad0cd97e96e2006b4763cb"
+ integrity sha512-6K8LaFlztlhZO7mwsZg7ClRsdLg3FJRzIIi6SZXDWmmSJc2x8dd2VkESbLXdk3p8cuvz71f36S0y8Zv2AxqvQw==
+
+"@types/d3-polygon@^2":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-polygon/-/d3-polygon-2.0.1.tgz#c2056594f85b512bc2b4f741caddd4b5448bc115"
+ integrity sha512-X3XTIwBxlzRIWe4yaD1KsmcfItjSPLTGL04QDyP08jyHDVsnz3+NZJMwtD4vCaTAVpGSjbqS+jrBo8cO2V/xMA==
+
+"@types/d3-quadtree@^2":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-quadtree/-/d3-quadtree-2.0.2.tgz#e3cd92b4e05318f98b0a16e780ba99ce7b13eb77"
+ integrity sha512-KgWL4jlz8QJJZX01E4HKXJ9FLU94RTuObsAYqsPp8YOAcYDmEgJIQJ+ojZcnKUAnrUb78ik8JBKWas5XZPqJnQ==
+
+"@types/d3-random@^2":
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-random/-/d3-random-2.2.1.tgz#551edbb71cb317dea2cf9c76ebe059d311eefacb"
+ integrity sha512-5vvxn6//poNeOxt1ZwC7QU//dG9QqABjy1T7fP/xmFHY95GnaOw3yABf29hiu5SR1Oo34XcpyHFbzod+vemQjA==
+
+"@types/d3-scale-chromatic@^2":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-2.0.1.tgz#495cbbae7273e0d0ff564cdc19aa6d2b9928da83"
+ integrity sha512-3EuZlbPu+pvclZcb1DhlymTWT2W+lYsRKBjvkH2ojDbCWDYavifqu1vYX9WGzlPgCgcS4Alhk1+zapXbGEGylQ==
+
+"@types/d3-scale@^3":
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-3.3.2.tgz#18c94e90f4f1c6b1ee14a70f14bfca2bd1c61d06"
+ integrity sha512-gGqr7x1ost9px3FvIfUMi5XA/F/yAf4UkUDtdQhpH92XCT0Oa7zkkRzY61gPVJq+DxpHn/btouw5ohWkbBsCzQ==
+ dependencies:
+ "@types/d3-time" "^2"
+
+"@types/d3-selection@^2":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-2.0.1.tgz#bc2816c96faff285d204dda72b79734d4f37d583"
+ integrity sha512-3mhtPnGE+c71rl/T5HMy+ykg7migAZ4T6gzU0HxpgBFKcasBrSnwRbYV1/UZR6o5fkpySxhWxAhd7yhjj8jL7g==
+
+"@types/d3-shape@^2":
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-2.1.3.tgz#35d397b9e687abaa0de82343b250b9897b8cacf3"
+ integrity sha512-HAhCel3wP93kh4/rq+7atLdybcESZ5bRHDEZUojClyZWsRuEMo3A52NGYJSh48SxfxEU6RZIVbZL2YFZ2OAlzQ==
+ dependencies:
+ "@types/d3-path" "^2"
+
+"@types/d3-time-format@^3":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-time-format/-/d3-time-format-3.0.1.tgz#1680fb6c41ab3a85db261ede296626668592246a"
+ integrity sha512-5GIimz5IqaRsdnxs4YlyTZPwAMfALu/wA4jqSiuqgdbCxUZ2WjrnwANqOtoBJQgeaUTdYNfALJO0Yb0YrDqduA==
+
+"@types/d3-time@^2":
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-2.1.1.tgz#743fdc821c81f86537cbfece07093ac39b4bc342"
+ integrity sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg==
+
+"@types/d3-timer@^2":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-2.0.1.tgz#ffb6620d290624f3726aa362c0c8a4b44c8d7200"
+ integrity sha512-TF8aoF5cHcLO7W7403blM7L1T+6NF3XMyN3fxyUolq2uOcFeicG/khQg/dGxiCJWoAcmYulYN7LYSRKO54IXaA==
+
+"@types/d3-transition@^2":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-2.0.2.tgz#d5ba1c26a3daeb0c5527d573d44b4c5ca9fae027"
+ integrity sha512-376TICEykdXOEA9uUIYpjshEkxfGwCPnkHUl8+6gphzKbf5NMnUhKT7wR59Yxrd9wtJ/rmE3SVLx6/8w4eY6Zg==
+ dependencies:
+ "@types/d3-selection" "^2"
+
+"@types/d3-zoom@^2":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-2.0.3.tgz#9eef8763600fa8be11b8cb0ed9144a395df6dffb"
+ integrity sha512-9X9uDYKk2U8w775OHj36s9Q7GkNAnJKGw6+sbkP5DpHSjELwKvTGzEK6+IISYfLpJRL/V3mRXMhgDnnJ5LkwJg==
+ dependencies:
+ "@types/d3-interpolate" "^2"
+ "@types/d3-selection" "^2"
+
+"@types/d3@^6.7.0":
+ version "6.7.5"
+ resolved "https://registry.yarnpkg.com/@types/d3/-/d3-6.7.5.tgz#6ae8034ea21db10fa3e31db1f670c5887d91d8a3"
+ integrity sha512-TUZ6zuT/KIvbHSv81kwAiO5gG5aTuoiLGnWR/KxHJ15Idy/xmGUXaaF5zMG+UMIsndcGlSHTmrvwRgdvZlNKaA==
+ dependencies:
+ "@types/d3-array" "^2"
+ "@types/d3-axis" "^2"
+ "@types/d3-brush" "^2"
+ "@types/d3-chord" "^2"
+ "@types/d3-color" "^2"
+ "@types/d3-contour" "^2"
+ "@types/d3-delaunay" "^5"
+ "@types/d3-dispatch" "^2"
+ "@types/d3-drag" "^2"
+ "@types/d3-dsv" "^2"
+ "@types/d3-ease" "^2"
+ "@types/d3-fetch" "^2"
+ "@types/d3-force" "^2"
+ "@types/d3-format" "^2"
+ "@types/d3-geo" "^2"
+ "@types/d3-hierarchy" "^2"
+ "@types/d3-interpolate" "^2"
+ "@types/d3-path" "^2"
+ "@types/d3-polygon" "^2"
+ "@types/d3-quadtree" "^2"
+ "@types/d3-random" "^2"
+ "@types/d3-scale" "^3"
+ "@types/d3-scale-chromatic" "^2"
+ "@types/d3-selection" "^2"
+ "@types/d3-shape" "^2"
+ "@types/d3-time" "^2"
+ "@types/d3-time-format" "^3"
+ "@types/d3-timer" "^2"
+ "@types/d3-transition" "^2"
+ "@types/d3-zoom" "^2"
+
"@types/fbemitter@*":
version "2.0.32"
resolved "https://registry.yarnpkg.com/@types/fbemitter/-/fbemitter-2.0.32.tgz#8ed204da0f54e9c8eaec31b1eec91e25132d082c"
@@ -1855,10 +2065,10 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.3.1.tgz#24691fa2b0c3ec8c0d34bfcfd495edac5593ebb4"
integrity sha512-N87VuQi7HEeRJkhzovao/JviiqKjDKMVKxKMfUvSKw+MbkbW8R0nA3fi/MQhhlxV2fQ+2ReM+/Nt4efdrJx3zA==
-"@types/node@12.0.0":
- version "12.0.0"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.0.tgz#d11813b9c0ff8aaca29f04cbc12817f4c7d656e5"
- integrity sha512-Jrb/x3HT4PTJp6a4avhmJCDEVrPdqLfl3e8GGMbpkGGdwAV5UGlIs4vVEfsHHfylZVOKZWpOqmqFH8CbfOZ6kg==
+"@types/node@^12.0.0":
+ version "12.20.16"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.16.tgz#1acf34f6456208f495dac0434dd540488d17f991"
+ integrity sha512-6CLxw83vQf6DKqXxMPwl8qpF8I7THFZuIwLt4TnNsumxkp1VsRZWT8txQxncT/Rl2UojTsFzWgDG4FRMwafrlA==
"@types/normalize-package-data@^2.4.0":
version "2.4.1"
@@ -3610,6 +3820,11 @@ commander@2.17.x:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
+commander@7:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
+ integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
+
commander@^2.12.1, commander@^2.19.0, commander@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
@@ -4045,6 +4260,250 @@ cyclist@^1.0.1:
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=
+"d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.0.1.tgz#ca45c263f5bb780ab5a34a6e1d3d5883fe4a8d14"
+ integrity sha512-l3Bh5o8RSoC3SBm5ix6ogaFW+J6rOUm42yOtZ2sQPCEvCqUMepeX7zgrlLLGIemxgOyo9s2CsWEidnLv5PwwRw==
+ dependencies:
+ internmap "1 - 2"
+
+d3-axis@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-3.0.0.tgz#c42a4a13e8131d637b745fc2973824cfeaf93322"
+ integrity sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==
+
+d3-brush@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-3.0.0.tgz#6f767c4ed8dcb79de7ede3e1c0f89e63ef64d31c"
+ integrity sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==
+ dependencies:
+ d3-dispatch "1 - 3"
+ d3-drag "2 - 3"
+ d3-interpolate "1 - 3"
+ d3-selection "3"
+ d3-transition "3"
+
+d3-chord@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-3.0.1.tgz#d156d61f485fce8327e6abf339cb41d8cbba6966"
+ integrity sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==
+ dependencies:
+ d3-path "1 - 3"
+
+"d3-color@1 - 3", d3-color@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.0.1.tgz#03316e595955d1fcd39d9f3610ad41bb90194d0a"
+ integrity sha512-6/SlHkDOBLyQSJ1j1Ghs82OIUXpKWlR0hCsw0XrLSQhuUPuCSmLQ1QPH98vpnQxMUQM2/gfAkUEWsupVpd9JGw==
+
+d3-contour@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-3.0.1.tgz#2c64255d43059599cd0dba8fe4cc3d51ccdd9bbd"
+ integrity sha512-0Oc4D0KyhwhM7ZL0RMnfGycLN7hxHB8CMmwZ3+H26PWAG0ozNuYG5hXSDNgmP1SgJkQMrlG6cP20HoaSbvcJTQ==
+ dependencies:
+ d3-array "2 - 3"
+
+d3-delaunay@6:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-6.0.2.tgz#7fd3717ad0eade2fc9939f4260acfb503f984e92"
+ integrity sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==
+ dependencies:
+ delaunator "5"
+
+"d3-dispatch@1 - 3", d3-dispatch@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e"
+ integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==
+
+"d3-drag@2 - 3", d3-drag@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba"
+ integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==
+ dependencies:
+ d3-dispatch "1 - 3"
+ d3-selection "3"
+
+"d3-dsv@1 - 3", d3-dsv@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-3.0.1.tgz#c63af978f4d6a0d084a52a673922be2160789b73"
+ integrity sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==
+ dependencies:
+ commander "7"
+ iconv-lite "0.6"
+ rw "1"
+
+"d3-ease@1 - 3", d3-ease@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4"
+ integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==
+
+d3-fetch@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-3.0.1.tgz#83141bff9856a0edb5e38de89cdcfe63d0a60a22"
+ integrity sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==
+ dependencies:
+ d3-dsv "1 - 3"
+
+d3-force@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-3.0.0.tgz#3e2ba1a61e70888fe3d9194e30d6d14eece155c4"
+ integrity sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==
+ dependencies:
+ d3-dispatch "1 - 3"
+ d3-quadtree "1 - 3"
+ d3-timer "1 - 3"
+
+"d3-format@1 - 3", d3-format@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.0.1.tgz#e41b81b2ab79277141ec1404aa5d05001da64084"
+ integrity sha512-hdL7+HBIohpgfolhBxr1KX47VMD6+vVD/oEFrxk5yhmzV2prk99EkFKYpXuhVkFpTgHdJ6/4bYcjdLPPXV4tIA==
+
+d3-geo@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-3.0.1.tgz#4f92362fd8685d93e3b1fae0fd97dc8980b1ed7e"
+ integrity sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==
+ dependencies:
+ d3-array "2.5.0 - 3"
+
+d3-hierarchy@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-3.0.1.tgz#0365342d54972e38ca05e9143e0ab1c60846b3b5"
+ integrity sha512-RlLTaofEoOrMK1JoXYIGhKTkJFI/6rFrYPgxy6QlZo2BcVc4HGTqEU0rPpzuMq5T/5XcMtAzv1XiLA3zRTfygw==
+
+"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d"
+ integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==
+ dependencies:
+ d3-color "1 - 3"
+
+"d3-path@1 - 3", d3-path@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.0.1.tgz#f09dec0aaffd770b7995f1a399152bf93052321e"
+ integrity sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==
+
+d3-polygon@3, d3-polygon@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-3.0.1.tgz#0b45d3dd1c48a29c8e057e6135693ec80bf16398"
+ integrity sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==
+
+"d3-quadtree@1 - 3", d3-quadtree@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz#6dca3e8be2b393c9a9d514dabbd80a92deef1a4f"
+ integrity sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==
+
+d3-random@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-3.0.1.tgz#d4926378d333d9c0bfd1e6fa0194d30aebaa20f4"
+ integrity sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==
+
+d3-scale-chromatic@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz#15b4ceb8ca2bb0dcb6d1a641ee03d59c3b62376a"
+ integrity sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==
+ dependencies:
+ d3-color "1 - 3"
+ d3-interpolate "1 - 3"
+
+d3-scale@4:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.0.tgz#294377ea1d7e5a31509ee648b98d7916ac0b34e3"
+ integrity sha512-foHQYKpWQcyndH1CGoHdUC4PECxTxonzwwBXGT8qu+Drb1FIc6ON6dG2P5f4hRRMkLiIKeWK7iFtdznDUrnuPQ==
+ dependencies:
+ d3-array "2.10.0 - 3"
+ d3-format "1 - 3"
+ d3-interpolate "1.2.0 - 3"
+ d3-time "2.1.1 - 3"
+ d3-time-format "2 - 4"
+
+"d3-selection@2 - 3", d3-selection@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31"
+ integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==
+
+d3-shape@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.0.1.tgz#9ccdfb28fd9b0d12f2d8aec234cd5c4a9ea27931"
+ integrity sha512-HNZNEQoDhuCrDWEc/BMbF/hKtzMZVoe64TvisFLDp2Iyj0UShB/E6/lBsLlJTfBMbYgftHj90cXJ0SEitlE6Xw==
+ dependencies:
+ d3-path "1 - 3"
+
+"d3-time-format@2 - 4", d3-time-format@4:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.0.0.tgz#930ded86a9de761702344760d8a25753467f28b7"
+ integrity sha512-nzaCwlj+ZVBIlFuVOT1RmU+6xb/7D5IcnhHzHQcBgS/aTa5K9fWZNN5LCXA27LgF5WxoSNJqKBbLcGMtM6Ca6A==
+ dependencies:
+ d3-time "1 - 3"
+
+"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.0.0.tgz#65972cb98ae2d4954ef5c932e8704061335d4975"
+ integrity sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==
+ dependencies:
+ d3-array "2 - 3"
+
+"d3-timer@1 - 3", d3-timer@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0"
+ integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==
+
+"d3-transition@2 - 3", d3-transition@3:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f"
+ integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==
+ dependencies:
+ d3-color "1 - 3"
+ d3-dispatch "1 - 3"
+ d3-ease "1 - 3"
+ d3-interpolate "1 - 3"
+ d3-timer "1 - 3"
+
+d3-zoom@3:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3"
+ integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==
+ dependencies:
+ d3-dispatch "1 - 3"
+ d3-drag "2 - 3"
+ d3-interpolate "1 - 3"
+ d3-selection "2 - 3"
+ d3-transition "2 - 3"
+
+d3@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/d3/-/d3-7.0.0.tgz#fe6036b38ba2026ff34223e208fd294db1b997da"
+ integrity sha512-t+jEKGO2jQiSBLJYYq6RFc500tsCeXBB4x41oQaSnZD3Som95nQrlw9XJGrFTMUOQOkwSMauWy9+8Tz1qm9UZw==
+ dependencies:
+ d3-array "3"
+ d3-axis "3"
+ d3-brush "3"
+ d3-chord "3"
+ d3-color "3"
+ d3-contour "3"
+ d3-delaunay "6"
+ d3-dispatch "3"
+ d3-drag "3"
+ d3-dsv "3"
+ d3-ease "3"
+ d3-fetch "3"
+ d3-force "3"
+ d3-format "3"
+ d3-geo "3"
+ d3-hierarchy "3"
+ d3-interpolate "3"
+ d3-path "3"
+ d3-polygon "3"
+ d3-quadtree "3"
+ d3-random "3"
+ d3-scale "4"
+ d3-scale-chromatic "3"
+ d3-selection "3"
+ d3-shape "3"
+ d3-time "3"
+ d3-time-format "4"
+ d3-timer "3"
+ d3-transition "3"
+ d3-zoom "3"
+
dargs@^4.0.1:
version "4.1.0"
resolved "https://registry.yarnpkg.com/dargs/-/dargs-4.1.0.tgz#03a9dbb4b5c2f139bf14ae53f0b8a2a6a86f4e17"
@@ -4221,6 +4680,13 @@ del@^3.0.0:
pify "^3.0.0"
rimraf "^2.2.8"
+delaunator@5:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-5.0.0.tgz#60f052b28bd91c9b4566850ebf7756efe821d81b"
+ integrity sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==
+ dependencies:
+ robust-predicates "^3.0.0"
+
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
@@ -5944,7 +6410,7 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24:
dependencies:
safer-buffer ">= 2.1.2 < 3"
-iconv-lite@^0.6.2:
+iconv-lite@0.6, iconv-lite@^0.6.2:
version "0.6.3"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
@@ -6134,6 +6600,11 @@ internal-ip@^3.0.1:
default-gateway "^2.6.0"
ipaddr.js "^1.5.2"
+"internmap@1 - 2":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.1.tgz#33d0fa016185397549fb1a14ea3dbe5a2949d1cd"
+ integrity sha512-Ujwccrj9FkGqjbY3iVoxD1VV+KdZZeENx0rphrtzmRXbFvkFO88L80BL/zeSIguX/7T+y8k04xqtgWgS5vxwxw==
+
interpret@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
@@ -10020,6 +10491,11 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
hash-base "^3.0.0"
inherits "^2.0.1"
+robust-predicates@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.1.tgz#ecde075044f7f30118682bd9fb3f123109577f9a"
+ integrity sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==
+
rsvp@^3.3.3:
version "3.6.2"
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a"
@@ -10037,7 +10513,7 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
-rw@^1.3.3:
+rw@1, rw@^1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
integrity sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=