Add link calculation app

Add link calculation app to odlux

Issue-ID: CCSDK-2562
Signed-off-by: Aijana Schumann <aijana.schumann@highstreet-technologies.com>
Change-Id: Ifc0a5b2a8bb974dfd85d70a9f05990b1f11925a3
Signed-off-by: Aijana Schumann <aijana.schumann@highstreet-technologies.com>
diff --git a/sdnr/wt/odlux/apps/apiDemo/pom.xml b/sdnr/wt/odlux/apps/apiDemo/pom.xml
index 52ff4bc..1756309 100644
--- a/sdnr/wt/odlux/apps/apiDemo/pom.xml
+++ b/sdnr/wt/odlux/apps/apiDemo/pom.xml
@@ -43,6 +43,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/sdnr/wt/odlux/apps/app-feature/pom.xml b/sdnr/wt/odlux/apps/app-feature/pom.xml
index bad5196..2aaf573 100644
--- a/sdnr/wt/odlux/apps/app-feature/pom.xml
+++ b/sdnr/wt/odlux/apps/app-feature/pom.xml
@@ -46,6 +46,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
@@ -92,5 +97,10 @@
             <artifactId>sdnr-wt-odlux-app-configurationApp</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>sdnr-wt-odlux-app-linkCalculationApp</artifactId>
+            <version>${project.version}</version>
+        </dependency>   
     </dependencies>
 </project>
diff --git a/sdnr/wt/odlux/apps/app-installer/pom.xml b/sdnr/wt/odlux/apps/app-installer/pom.xml
index 65ee924..1bf55ed 100755
--- a/sdnr/wt/odlux/apps/app-installer/pom.xml
+++ b/sdnr/wt/odlux/apps/app-installer/pom.xml
@@ -122,6 +122,12 @@
             <artifactId>sdnr-wt-odlux-app-configurationApp</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>sdnr-wt-odlux-app-linkCalculationApp</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
     </dependencies>
 
     <build>
diff --git a/sdnr/wt/odlux/apps/configurationApp/pom.xml b/sdnr/wt/odlux/apps/configurationApp/pom.xml
index f02644a..9f92c99 100644
--- a/sdnr/wt/odlux/apps/configurationApp/pom.xml
+++ b/sdnr/wt/odlux/apps/configurationApp/pom.xml
@@ -43,6 +43,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/baseProps.ts b/sdnr/wt/odlux/apps/configurationApp/src/components/baseProps.ts
index ec49191..8f7300c 100644
--- a/sdnr/wt/odlux/apps/configurationApp/src/components/baseProps.ts
+++ b/sdnr/wt/odlux/apps/configurationApp/src/components/baseProps.ts
@@ -18,4 +18,4 @@
 
 import { ViewElement } from "../models/uiModels";
 
-export type baseProps = { value: ViewElement, inputValue: string, readOnly: boolean, disabled: boolean, onChange(newValue: string): void };
\ No newline at end of file
+export type BaseProps<TValue = string> = { value: ViewElement, inputValue: TValue, readOnly: boolean, disabled: boolean, onChange(newValue: TValue): void };
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/ifWhenTextInput.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/ifWhenTextInput.tsx
index 6735888..62ddeb2 100644
--- a/sdnr/wt/odlux/apps/configurationApp/src/components/ifWhenTextInput.tsx
+++ b/sdnr/wt/odlux/apps/configurationApp/src/components/ifWhenTextInput.tsx
@@ -24,38 +24,59 @@
 import { InputProps } from "@material-ui/core/Input";
 
 const useStyles = makeStyles((theme: Theme) =>
-    createStyles({
-        iconDark: {
-            color: '#ff8800'
-        },
-        iconLight: {
-            color: 'orange'
-        },
-        padding: {
-            paddingLeft: 10,
-            paddingRight: 10
-        },
-    }),
+  createStyles({
+    iconDark: {
+      color: '#ff8800'
+    },
+    iconLight: {
+      color: 'orange'
+    },
+    padding: {
+      paddingLeft: 10,
+      paddingRight: 10
+    },
+  }),
 );
 
-type ifwhenProps = { element: ViewElementBase, id: any, label: any, style: any, helperText: string, error: boolean, toogleTooltip(value: boolean): void, [x: string]: any };
+type IfwhenProps = InputProps & {
+  label: string;
+  element: ViewElementBase;
+  helperText: string;
+  error: boolean;
+  onChangeTooltipVisuability(value: boolean): void;
+};
 
-export const IfWhenTextInput = (props: ifwhenProps) => {
+export const IfWhenTextInput = (props: IfwhenProps) => {
 
-    const { element, toogleTooltip, id, label, helperText: errorText, error, style, ...otherProps } = props;
-    const classes = useStyles();
+  const { element, onChangeTooltipVisuability: toogleTooltip, id, label, helperText: errorText, error, style, ...otherProps } = props;
+  const classes = useStyles();
 
 
-    const ifFeature = element.ifFeature ? <Tooltip onMouseMove={e => props.toogleTooltip(false)} onMouseOut={e => props.toogleTooltip(true)} title={element.ifFeature}><InputAdornment position="start"><FontAwesomeIcon icon={faAdjust} className={classes.iconDark}></FontAwesomeIcon></InputAdornment></Tooltip> : null;
-    const whenFeature = element.when ? (<Tooltip className={classes.padding} onMouseMove={e => props.toogleTooltip(false)} onMouseOut={e => props.toogleTooltip(true)} title={element.when}>
-        <InputAdornment className={classes.padding} position="end"><FontAwesomeIcon icon={faAdjust} className={classes.iconLight}></FontAwesomeIcon></InputAdornment></Tooltip>) : null;
+  const ifFeature = element.ifFeature
+    ? (
+        <Tooltip onMouseMove={e => props.onChangeTooltipVisuability(false)} onMouseOut={e => props.onChangeTooltipVisuability(true)} title={element.ifFeature}>
+          <InputAdornment position="start">
+            <FontAwesomeIcon icon={faAdjust} className={classes.iconDark} />
+          </InputAdornment>
+        </Tooltip>
+      )
+    : null;
 
-    return (
-        <FormControl error={error} style={style}>
-            <InputLabel htmlFor={id} >{label}</InputLabel>
-            <Input  {...otherProps} id={id} endAdornment={<div>{ifFeature}{whenFeature}</div>} />
-            <FormHelperText>{errorText}</FormHelperText>
-        </FormControl>
+  const whenFeature = element.when
+    ? (
+        <Tooltip className={classes.padding} onMouseMove={() => props.onChangeTooltipVisuability(false)} onMouseOut={() => props.onChangeTooltipVisuability(true)} title={element.when}>
+          <InputAdornment className={classes.padding} position="end">
+            <FontAwesomeIcon icon={faAdjust} className={classes.iconLight}/>
+          </InputAdornment>
+        </Tooltip>
+      ) 
+    : null;
 
-    );
+  return (
+    <FormControl error={error} style={style}>
+      <InputLabel htmlFor={id} >{label}</InputLabel>
+      <Input id={id} endAdornment={<div>{ifFeature}{whenFeature}</div>} {...otherProps}  />
+      <FormHelperText>{errorText}</FormHelperText>
+    </FormControl>
+  );
 }
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementBoolean.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementBoolean.tsx
index cc141ee..2fbbf95 100644
--- a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementBoolean.tsx
+++ b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementBoolean.tsx
@@ -16,29 +16,28 @@
  * ============LICENSE_END==========================================================================
  */
 
-import { ViewElementBoolean } from "../models/uiModels";
 import * as React from "react"
 import { MenuItem, FormHelperText, Select, FormControl, InputLabel } from "@material-ui/core";
-import { baseProps } from "./baseProps";
 
-type booleanInputProps = baseProps;
+import { ViewElementBoolean } from "../models/uiModels";
+import { BaseProps } from "./baseProps";
 
-export const UiElementBoolean = (props: booleanInputProps) => {
+type BooleanInputProps = BaseProps<boolean>;
+
+export const UiElementBoolean = (props: BooleanInputProps) => {
 
     const element = props.value as ViewElementBoolean;
 
-    let error = "";
     const value = String(props.inputValue).toLowerCase();
-    if (element.mandatory && value !== "true" && value !== "false") {
-        error = "Error";
-    }
+    const mandetoryError = element.mandatory && value !== 'true' && value !== 'false';
+    
     return (!props.readOnly || element.id != null
         ? (<FormControl style={{ width: 485, marginLeft: 20, marginRight: 20 }}>
             <InputLabel htmlFor={`select-${element.id}`} >{element.label}</InputLabel>
             <Select
                 required={!!element.mandatory}
-                error={!!error}
-                onChange={(e) => { props.onChange(e.target.value as any) }}
+                error={mandetoryError}
+                onChange={(e) => { props.onChange(e.target.value === 'true') }}
                 readOnly={props.readOnly}
                 disabled={props.disabled}
                 value={value}
@@ -51,7 +50,7 @@
                 <MenuItem value={'false'}>{element.falseValue || 'False'}</MenuItem>
 
             </Select>
-            <FormHelperText>{error}</FormHelperText>
+            <FormHelperText>{mandetoryError ? "Value is mandetory" : ""}</FormHelperText>
         </FormControl>)
         : null
     );
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementNumber.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementNumber.tsx
index cf46205..ac4afc1 100644
--- a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementNumber.tsx
+++ b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementNumber.tsx
@@ -19,59 +19,52 @@
 import { ViewElementNumber } from "models/uiModels";
 import { Tooltip, InputAdornment } from "@material-ui/core";
 import * as React from 'react';
-import { baseProps } from "./baseProps";
+import { BaseProps } from "./baseProps";
 import { IfWhenTextInput } from "./ifWhenTextInput";
 import { checkRange } from "./verifyer";
 
-type numberInputProps = baseProps;
+type numberInputProps = BaseProps<number>;
 
 export const UiElementNumber = (props: numberInputProps) => {
 
 
-    const [error, setError] = React.useState(false);
-    const [helperText, setHelperText] = React.useState("");
-    const [isTooltipVisible, setTooltipVisibility] = React.useState(true);
+  const [error, setError] = React.useState(false);
+  const [helperText, setHelperText] = React.useState("");
+  const [isTooltipVisible, setTooltipVisibility] = React.useState(true);
 
-    const element = props.value as ViewElementNumber;
+  const element = props.value as ViewElementNumber;
 
-    const verifyValue = (data: string) => {
-
-        if (data.trim().length > 0) {
-            const num = Number(data);
-            if (!isNaN(num)) {
-                const result = checkRange(element, num);
-                if (result.length > 0) {
-                    setError(true);
-                    setHelperText(result);
-                } else {
-                    setError(false);
-                    setHelperText("");
-                }
-            } else {
-                setError(true);
-                setHelperText("Input is not a number.");
-            }
-        } else {
-            setError(false);
-            setHelperText("");
-        }
-
-        props.onChange(data);
+  const verifyValue = (data: string) => {
+    const num = Number(data);
+    if (!isNaN(num)) {
+      const result = checkRange(element, num);
+      if (result.length > 0) {
+        setError(true);
+        setHelperText(result);
+      } else {
+        setError(false);
+        setHelperText("");
+      }
+    } else {
+      setError(true);
+      setHelperText("Input is not a number.");
     }
+    props.onChange(num);
+  }
 
-    return (
-        <Tooltip title={isTooltipVisible ? element.description || '' : ''}>
-            <IfWhenTextInput element={element} toogleTooltip={(val: boolean) => setTooltipVisibility(val)}
-                spellCheck={false} autoFocus margin="dense"
-                id={element.id} label={element.label} type="text" value={props.inputValue}
-                style={{ width: 485, marginLeft: 20, marginRight: 20 }}
-                onChange={(e: any) => { verifyValue(e.target.value) }}
-                error={error}
-                readOnly={props.readOnly}
-                disabled={props.disabled}
-                helperText={helperText}
-                startAdornment={element.units != null ? <InputAdornment position="start">{element.units}</InputAdornment> : undefined}
-            />
-        </Tooltip>
-    );
+  return (
+    <Tooltip title={isTooltipVisible ? element.description || '' : ''}>
+      <IfWhenTextInput element={element} onChangeTooltipVisuability={setTooltipVisibility}
+        spellCheck={false} autoFocus margin="dense"
+        id={element.id} label={element.label} type="text" value={props.inputValue}
+        style={{ width: 485, marginLeft: 20, marginRight: 20 }}
+        onChange={(e) => { verifyValue(e.target.value) }}
+        error={error}
+        readOnly={props.readOnly}
+        disabled={props.disabled}
+        helperText={helperText}
+        startAdornment={element.units != null ? <InputAdornment position="start">{element.units}</InputAdornment> : undefined}
+      />
+    </Tooltip>
+  );
 }
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementSelection.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementSelection.tsx
index 8b0b890..1cec754 100644
--- a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementSelection.tsx
+++ b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementSelection.tsx
@@ -17,13 +17,11 @@
  */
 
 import * as React from 'react';
-import { baseProps } from './baseProps';
+import { BaseProps } from './baseProps';
 import { ViewElementSelection } from '../models/uiModels'
 import { FormControl, InputLabel, Select, FormHelperText, MenuItem } from '@material-ui/core';
 
-
-
-type selectionProps = baseProps;
+type selectionProps = BaseProps;
 
 export const UiElementSelection = (props: selectionProps) => {
 
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementString.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementString.tsx
index 43c60b5..95841b7 100644
--- a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementString.tsx
+++ b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementString.tsx
@@ -16,14 +16,14 @@
  * ============LICENSE_END==========================================================================
  */
 
+import * as React from "react"
 import { Tooltip, TextField } from "@material-ui/core";
 import { ViewElementString } from "../models/uiModels";
-import * as React from "react"
-import { baseProps } from "./baseProps";
+import { BaseProps } from "./baseProps";
 import { IfWhenTextInput } from "./ifWhenTextInput";
 import { checkRange, checkPattern } from "./verifyer";
 
-type stringEntryProps = baseProps & { isKey: boolean };
+type stringEntryProps = BaseProps & { isKey: boolean };
 
 export const UiElementString = (props: stringEntryProps) => {
 
@@ -40,9 +40,9 @@
             let errorMessage = "";
             const result = checkRange(element, data.length);
 
-            if (result.length > 0)
+            if (result.length > 0) {
                 errorMessage += result;
-
+            }
 
             const patternResult = checkPattern(element.pattern, data)
 
@@ -69,7 +69,7 @@
 
     return (
         <Tooltip title={isTooltipVisible ? element.description || '' : ''}>
-            <IfWhenTextInput element={element} toogleTooltip={(val: boolean) => setTooltipVisibility(val)}
+            <IfWhenTextInput element={element} onChangeTooltipVisuability={setTooltipVisibility}
                 spellCheck={false} autoFocus margin="dense"
                 id={element.id} label={props.isKey ? "🔑 " + element.label : element.label} type="text" value={props.inputValue}
                 style={{ width: 485, marginLeft: 20, marginRight: 20 }}
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementUnion.tsx b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementUnion.tsx
index 25378d7..669e393 100644
--- a/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementUnion.tsx
+++ b/sdnr/wt/odlux/apps/configurationApp/src/components/uiElementUnion.tsx
@@ -17,77 +17,75 @@
  */
 
 import * as React from 'react'
-import { baseProps } from './baseProps';
+import { BaseProps } from './baseProps';
 import { Tooltip } from '@material-ui/core';
 import { IfWhenTextInput } from './ifWhenTextInput';
 import { ViewElementUnion, isViewElementString, isViewElementNumber, isViewElementObject, ViewElementNumber } from '../models/uiModels';
 import { checkRange, checkPattern } from './verifyer';
 
-type UiElementUnionProps = { isKey: boolean } & baseProps;
+type UiElementUnionProps = { isKey: boolean } & BaseProps;
 
 export const UIElementUnion = (props: UiElementUnionProps) => {
 
-    const [isError, setError] = React.useState(false);
-    const [helperText, setHelperText] = React.useState("");
-    const [isTooltipVisible, setTooltipVisibility] = React.useState(true);
+  const [isError, setError] = React.useState(false);
+  const [helperText, setHelperText] = React.useState("");
+  const [isTooltipVisible, setTooltipVisibility] = React.useState(true);
 
-    const element = props.value as ViewElementUnion;
+  const element = props.value as ViewElementUnion;
 
-    const verifyValues = (data: string) => {
+  const verifyValues = (data: string) => {
 
-        let foundObjectElements = 0;
-        let errorMessage = "";
-        let isPatternCorrect = null;
+    let foundObjectElements = 0;
+    let errorMessage = "";
+    let isPatternCorrect = null;
 
-        for (let i = 0; i < element.elements.length; i++) {
-            const unionElement = element.elements[i];
+    for (let i = 0; i < element.elements.length; i++) {
+      const unionElement = element.elements[i];
 
-            if (isViewElementNumber(unionElement)) {
+      if (isViewElementNumber(unionElement)) {
 
-                errorMessage = checkRange(unionElement, Number(data));
+        errorMessage = checkRange(unionElement, Number(data));
 
-            } else if (isViewElementString(unionElement)) {
-                errorMessage += checkRange(unionElement, data.length);
-                isPatternCorrect = checkPattern(unionElement.pattern, data).isValid;
+      } else if (isViewElementString(unionElement)) {
+        errorMessage += checkRange(unionElement, data.length);
+        isPatternCorrect = checkPattern(unionElement.pattern, data).isValid;
 
 
-            } else if (isViewElementObject(unionElement)) {
-                foundObjectElements++;
-            }
+      } else if (isViewElementObject(unionElement)) {
+        foundObjectElements++;
+      }
 
-            if (isPatternCorrect || errorMessage.length === 0) {
-                break;
-            }
-        }
+      if (isPatternCorrect || errorMessage.length === 0) {
+        break;
+      }
+    }
 
-        if (errorMessage.length > 0 || isPatternCorrect !== null && !isPatternCorrect) {
-            setError(true);
-            setHelperText("Input is wrong.");
-        } else {
-            setError(false);
-            setHelperText("");
-        }
+    if (errorMessage.length > 0 || isPatternCorrect !== null && !isPatternCorrect) {
+      setError(true);
+      setHelperText("Input is wrong.");
+    } else {
+      setError(false);
+      setHelperText("");
+    }
 
-        if (foundObjectElements > 0 && foundObjectElements != element.elements.length) {
-            throw new Error(`The union element ${element.id} can't be changed.`);
+    if (foundObjectElements > 0 && foundObjectElements != element.elements.length) {
+      throw new Error(`The union element ${element.id} can't be changed.`);
 
-        } else {
-            props.onChange(data);
-        }
-    };
+    } else {
+      props.onChange(data);
+    }
+  };
 
-
-
-    return <Tooltip title={isTooltipVisible ? element.description || '' : ''}>
-        <IfWhenTextInput element={element} toogleTooltip={(val: boolean) => setTooltipVisibility(val)}
-            spellCheck={false} autoFocus margin="dense"
-            id={element.id} label={props.isKey ? "🔑 " + element.label : element.label} type="text" value={props.inputValue}
-            onChange={(e: any) => { verifyValues(e.target.value) }}
-            error={isError}
-            style={{ width: 485, marginLeft: 20, marginRight: 20 }}
-            readOnly={props.readOnly}
-            disabled={props.disabled}
-            helperText={helperText}
-        />
-    </Tooltip>;
+  return <Tooltip title={isTooltipVisible ? element.description || '' : ''}>
+    <IfWhenTextInput element={element} onChangeTooltipVisuability={setTooltipVisibility}
+      spellCheck={false} autoFocus margin="dense"
+      id={element.id} label={props.isKey ? "🔑 " + element.label : element.label} type="text" value={props.inputValue}
+      onChange={(e: any) => { verifyValues(e.target.value) }}
+      error={isError}
+      style={{ width: 485, marginLeft: 20, marginRight: 20 }}
+      readOnly={props.readOnly}
+      disabled={props.disabled}
+      helperText={helperText}
+    />
+  </Tooltip>;
 }
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx b/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx
index 385f3b5..6465feb 100644
--- a/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx
+++ b/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx
@@ -284,8 +284,12 @@
   private renderUIElement = (uiElement: ViewElement, viewData: { [key: string]: any }, keyProperty: string | undefined, editMode: boolean, isNew: boolean) => {
     const isKey = (uiElement.label === keyProperty);
     const canEdit = editMode && (isNew || (uiElement.config && !isKey));
-    if (isViewElementEmpty(uiElement)) {
+    
+    // do not show elements w/o any value from the backend
+    if (viewData[uiElement.id] == null && !editMode) {
       return null;
+    } else  if (isViewElementEmpty(uiElement)) {
+      return null;  
     } else if (isViewElementSelection(uiElement)) {
 
       return <UiElementSelection
@@ -300,7 +304,7 @@
     } else if (isViewElementBoolean(uiElement)) {
       return <UiElementBoolean
         key={uiElement.id}
-        inputValue={viewData[uiElement.id] || ''}
+        inputValue={viewData[uiElement.id] == null ? '' : viewData[uiElement.id]}
         value={uiElement}
         readOnly={!canEdit}
         disabled={editMode && !canEdit}
@@ -309,7 +313,7 @@
     } else if (isViewElementString(uiElement)) {
       return <UiElementString
         key={uiElement.id}
-        inputValue={viewData[uiElement.id] || ''}
+        inputValue={viewData[uiElement.id] == null ? '' : viewData[uiElement.id]}
         value={uiElement}
         isKey={isKey}
         readOnly={!canEdit}
diff --git a/sdnr/wt/odlux/apps/connectApp/pom.xml b/sdnr/wt/odlux/apps/connectApp/pom.xml
index 0bbd806..6f984da 100644
--- a/sdnr/wt/odlux/apps/connectApp/pom.xml
+++ b/sdnr/wt/odlux/apps/connectApp/pom.xml
@@ -43,6 +43,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/sdnr/wt/odlux/apps/connectApp/src/views/connectView.tsx b/sdnr/wt/odlux/apps/connectApp/src/views/connectView.tsx
index a7feae9..86861fa 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/views/connectView.tsx
+++ b/sdnr/wt/odlux/apps/connectApp/src/views/connectView.tsx
@@ -106,8 +106,8 @@
       <>
         <AppBar position="static">
           <Tabs value={activePanelId} onChange={this.onHandleTabChange} aria-label="simple tabs example">
-            <Tab label="Network Elements" value="NetworkElements" />
-            <Tab label="Connection Status Log" value="ConnectionStatusLog" />
+            <Tab aria-lablel="network-elements-list-tab" label="Network Elements" value="NetworkElements" />
+            <Tab aria-lablel="connection-status-log-tab" label="Connection Status Log" value="ConnectionStatusLog" />
           </Tabs>
         </AppBar>
         {activePanelId === 'NetworkElements'
diff --git a/sdnr/wt/odlux/apps/demoApp/pom.xml b/sdnr/wt/odlux/apps/demoApp/pom.xml
index 414c71f..bb0384b 100644
--- a/sdnr/wt/odlux/apps/demoApp/pom.xml
+++ b/sdnr/wt/odlux/apps/demoApp/pom.xml
@@ -43,6 +43,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/sdnr/wt/odlux/apps/eventLogApp/pom.xml b/sdnr/wt/odlux/apps/eventLogApp/pom.xml
index 70a25e4..7b762c6 100644
--- a/sdnr/wt/odlux/apps/eventLogApp/pom.xml
+++ b/sdnr/wt/odlux/apps/eventLogApp/pom.xml
@@ -43,6 +43,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/sdnr/wt/odlux/apps/faultApp/pom.xml b/sdnr/wt/odlux/apps/faultApp/pom.xml
index 00b758e..7818eaa 100644
--- a/sdnr/wt/odlux/apps/faultApp/pom.xml
+++ b/sdnr/wt/odlux/apps/faultApp/pom.xml
@@ -43,6 +43,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/sdnr/wt/odlux/apps/faultApp/src/components/faultStatus.tsx b/sdnr/wt/odlux/apps/faultApp/src/components/faultStatus.tsx
index 1ec463f..b711b03 100644
--- a/sdnr/wt/odlux/apps/faultApp/src/components/faultStatus.tsx
+++ b/sdnr/wt/odlux/apps/faultApp/src/components/faultStatus.tsx
@@ -57,12 +57,20 @@
     const { classes, faultStatus } = this.props;
 
     return (
-      <Typography variant="body1" color="inherit" >
+      <>
+      <Typography variant="body1" color="inherit" aria-label="critical-alarms">
         Alarm Status: <FontAwesomeIcon className={`${classes.icon} ${classes.critical}`} icon={faExclamationTriangle} /> { faultStatus.critical  } |
+        </Typography>
+        <Typography variant="body1" color="inherit" aria-label="major-alarms">
         <FontAwesomeIcon className={`${classes.icon} ${classes.major}`} icon={faExclamationTriangle} /> { faultStatus.major } |
+        </Typography>
+        <Typography variant="body1" color="inherit" aria-label="minor-alarms">
         <FontAwesomeIcon className={`${classes.icon} ${classes.minor}`} icon={faExclamationTriangle} /> { faultStatus.minor } |
+        </Typography>
+        <Typography variant="body1" color="inherit" aria-label="warning-alarms">
         <FontAwesomeIcon className={`${classes.icon} ${classes.warning}`} icon={faExclamationTriangle} /> { faultStatus.warning } |
       </Typography>
+      </>
     );
   };
 }
diff --git a/sdnr/wt/odlux/apps/faultApp/src/views/faultApplication.tsx b/sdnr/wt/odlux/apps/faultApp/src/views/faultApplication.tsx
index 1072154..7c29fec 100644
--- a/sdnr/wt/odlux/apps/faultApp/src/views/faultApplication.tsx
+++ b/sdnr/wt/odlux/apps/faultApp/src/views/faultApplication.tsx
@@ -138,9 +138,9 @@
       <>
         <AppBar position="static" >
           <Tabs value={activePanelId} onChange={this.onHandleTabChange} aria-label="fault tabs">
-            <Tab label="Current Problem List" value="CurrentProblem" />
-            <Tab label={`Alarm Notifications (${this.props.faultNotifications.faults.length})`} value="AlarmNotifications" />
-            <Tab label="Alarm Log" value="AlarmLog" />
+            <Tab aria-label="current-problem-list-tab" label="Current Problem List" value="CurrentProblem" />
+            <Tab aria-label="alarm-notifications-list-tab" label={`Alarm Notifications (${this.props.faultNotifications.faults.length})`} value="AlarmNotifications" />
+            <Tab aria-label="alarm-log-tab" label="Alarm Log" value="AlarmLog" />
           </Tabs>
         </AppBar>
         {
diff --git a/sdnr/wt/odlux/apps/helpApp/pom.xml b/sdnr/wt/odlux/apps/helpApp/pom.xml
index 3c8410b..6ada280 100644
--- a/sdnr/wt/odlux/apps/helpApp/pom.xml
+++ b/sdnr/wt/odlux/apps/helpApp/pom.xml
@@ -43,6 +43,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/sdnr/wt/odlux/apps/helpApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml b/sdnr/wt/odlux/apps/helpApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml
index 0fe9cd0..aaf395c 100644
--- a/sdnr/wt/odlux/apps/helpApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/sdnr/wt/odlux/apps/helpApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -25,6 +25,6 @@
     <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="helpApp"/>
-        <property name="index" value="100"/>
+        <property name="index" value="200"/>
     </bean>
 </blueprint>
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/inventoryApp/pom.xml b/sdnr/wt/odlux/apps/inventoryApp/pom.xml
index fe4ffcd..1184319 100644
--- a/sdnr/wt/odlux/apps/inventoryApp/pom.xml
+++ b/sdnr/wt/odlux/apps/inventoryApp/pom.xml
@@ -43,6 +43,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/.babelrc b/sdnr/wt/odlux/apps/linkCalculationApp/.babelrc
new file mode 100644
index 0000000..3d8cd12
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/.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/linkCalculationApp/package.json b/sdnr/wt/odlux/apps/linkCalculationApp/package.json
new file mode 100644
index 0000000..40e1be9
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/package.json
@@ -0,0 +1,40 @@
+{
+  "name": "@odlux/linkcalculation-app",
+  "version": "0.1.0",
+  "description": "A react based modular UI to do link analysis.",
+  "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": "Mohammad Boroon",
+  "license": "Apache-2.0",
+  "dependencies": {
+    "@odlux/framework": "*"
+  },
+  "peerDependencies": {
+    "@types/react": "16.9.19",
+    "@types/react-dom": "16.9.5",
+    "@types/react-router-dom": "4.3.1",
+    "@material-ui/core": "4.9.0",
+    "@material-ui/icons": "4.5.1",
+    "@types/classnames": "2.2.6",
+    "@types/flux": "3.1.8",
+    "@types/jquery": "3.3.10",
+    "jquery": "3.3.1",
+    "react": "16.12.0",
+    "react-dom": "16.12.0",
+    "react-router-dom": "4.3.1"
+  }
+}
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/pom.xml b/sdnr/wt/odlux/apps/linkCalculationApp/pom.xml
new file mode 100644
index 0000000..8f057bd
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/pom.xml
@@ -0,0 +1,176 @@
+<?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>odlparent</artifactId>
+        <version>2.0.1-SNAPSHOT</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+    <artifactId>sdnr-wt-odlux-app-linkCalculationApp</artifactId>
+    <version>1.0.1-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>
+        <checkstyle.skip>true</checkstyle.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>v10.16.3</nodeVersion>
+                            <yarnVersion>v1.19.0</yarnVersion>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>yarn build</id>
+                        <goals>
+                            <goal>yarn</goal>
+                        </goals>
+                        <configuration>
+                            <arguments>run build</arguments>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Import-Package>org.onap.ccsdk.features.sdnr.wt.odlux.model.*,com.opensymphony.*</Import-Package>
+                        <Private-Package/>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/actions/commonLinkCalculationActions.ts b/sdnr/wt/odlux/apps/linkCalculationApp/src/actions/commonLinkCalculationActions.ts
new file mode 100644
index 0000000..555954d
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/actions/commonLinkCalculationActions.ts
@@ -0,0 +1,104 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2020 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 { Action } from "../../../../framework/src/flux/action";
+import { Dispatch } from "../../../../framework/src/flux/store";
+import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore";
+
+
+export class UpdateLinkIdAction extends Action{
+    constructor(public linkId: string){
+        super();
+    }
+}
+
+export class UpdateFrequencyAction extends Action{
+    constructor(public frequency: number){
+        super();
+    }
+}
+export class UpdateSiteAction extends Action{
+    constructor(
+        public siteA?: any,
+        public siteB?: any
+         ){
+        super();
+    }
+}
+export class UpdateRainAttAction extends Action{
+    
+    constructor(public rainAtt: number){
+        super();
+    }
+}
+export class UpdateRainValAction extends Action{
+    constructor(public rainVal: number){
+        super();
+    }
+}
+
+export class updateHideForm extends Action{
+    constructor(public formView: boolean){
+        super();
+    }
+}
+export class UpdateDistanceAction extends Action{
+    constructor(public distance: number){
+        super();
+    }
+}
+
+export class UpdateFslCalculation extends Action{
+    constructor(public fsl: number){
+        super();
+    }
+}
+
+
+export class UpdateLatLonAction extends Action{
+    constructor(
+        public Lat1: number,
+        public Lon1:number,
+        public Lat2: number, 
+        public Lon2: number
+        ){
+        super();
+        
+    }
+}
+export class isCalculationServerReachableAction extends Action{
+    constructor(public reachable: boolean){
+        super();
+    }
+}
+
+// export const checkCalculationsServerConnectivityAction = (callback: Promise<any>) => (dispatcher: Dispatch, getState: () => IApplicationStoreState)=>{
+//     callback
+//     .then(res =>{ 
+//         const {linkCalculation:{calculations: {isCalculationServerAvailable}}} = getState();
+//         if(!isToplogyServerAvailable){
+//             dispatcher(new IsTopologyServerReachableAction(true))
+//         }
+//     })
+//     .catch(error=>{
+//         const {network:{connectivity: {isToplogyServerAvailable}}} = getState();
+//         if(isToplogyServerAvailable){
+//            dispatcher(new IsTopologyServerReachableAction(false))
+//         }
+//     })
+// }
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/components/connectionInfo.tsx b/sdnr/wt/odlux/apps/linkCalculationApp/src/components/connectionInfo.tsx
new file mode 100644
index 0000000..c798e48
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/components/connectionInfo.tsx
@@ -0,0 +1,55 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2020 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 { IApplicationStoreState } from "../../../../framework/src/store/applicationStore";
+import connect, { IDispatcher, Connect } from "../../../../framework/src/flux/connect";
+import { Paper, Typography } from "@material-ui/core";
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
+
+
+type props = Connect<typeof mapStateToProps, typeof mapDispatchToProps>;
+
+const ConnectionInfo: React.FunctionComponent<props> = (props) => {
+
+    return (
+        (props.isCalculationServerReachable === false)?  <Paper style={{padding:5, position: 'absolute', top: 160, width: 230, left:"40%"}}>
+        <div style={{display: 'flex', flexDirection: 'column'}}>
+        <div style={{'alignSelf': 'center', marginBottom:5}}> <Typography> <FontAwesomeIcon icon={faExclamationTriangle} /> Connection Error</Typography></div>
+        {props.isCalculationServerReachable === false && <Typography> Calculation data can't be loaded.</Typography>}
+        </div>
+    </Paper> : null
+)}
+
+const mapStateToProps = (state: IApplicationStoreState) => ({
+    isCalculationServerReachable: state.linkCalculation.calculations.reachable
+});
+
+
+
+const mapDispatchToProps = (dispatcher: IDispatcher) => ({
+
+    //zoomToSearchResult: (lat: number, lon: number) => dispatcher.dispatch(new ZoomToSearchResultAction(lat, lon))
+
+});;
+
+
+export default connect(mapStateToProps,mapDispatchToProps)(ConnectionInfo)
+
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/components/denseTable.tsx b/sdnr/wt/odlux/apps/linkCalculationApp/src/components/denseTable.tsx
new file mode 100644
index 0000000..96d6f4e
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/components/denseTable.tsx
@@ -0,0 +1,121 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2020 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 Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableContainer from '@material-ui/core/TableContainer';
+import TableHead from '@material-ui/core/TableHead';
+import TableRow from '@material-ui/core/TableRow';
+import Paper from '@material-ui/core/Paper';
+import { makeStyles, Button, Tooltip } from '@material-ui/core';
+
+type props = { headers: string[], width: number, height:number,  navigate?(applicationName: string, path?: string):void, onLinkClick?(id: string): void, data: any[], hover: boolean, onClick?(id: string): void, actions?:boolean  };
+
+
+const styles = makeStyles({
+    container: {
+        overflow:"auto"
+    },
+    button: {
+        margin: 0,
+        padding: "6px 6px",
+        minWidth: 'unset'
+      }
+    
+  });
+  
+
+const DenseTable: React.FunctionComponent<props> = (props) => {
+
+    const classes = styles();
+
+    const handleClick = (event: any, id: string) =>{
+        event.preventDefault();
+        props.onClick !== undefined && props.onClick(id);
+
+    }
+
+    const handleHover = (event: any, id: string) =>{
+        event.preventDefault();
+
+    }
+
+    return (
+        <Paper style={{borderRadius:"0px", width:props.width, height:props.height}} className={classes.container}>
+       
+            <Table stickyHeader size="small" aria-label="a dense table" >
+                <TableHead>
+                    <TableRow>
+                        {
+                            props.headers.map((data) => {
+                                return <TableCell>{data}</TableCell>
+                            })
+                        }
+                    </TableRow>
+                </TableHead>
+                <TableBody>
+                    {props.data.map((row, index) => {
+
+                        
+                        var filteredRows = Object.keys(row).filter(function(e) { if(e!=="simulatorId") return row });
+                     
+                        //var filteredRows = Object.keys(row).filter(function(e) { if(e!=="simulatorId") return row[e] });
+                        var values = Object.keys(row).map(function(e) {  if(e!=="simulatorId"){ return row[e];} else return undefined });
+                       
+
+                        return (
+                            <TableRow key={index} hover={props.hover} onMouseOver={e => handleHover(e,row.name)} onClick={ e =>  handleClick(e, row.name)}>
+
+                                {
+                                    values.map((data:any) => {
+                                       
+                                        if(data!== undefined)
+                                        return <TableCell >  {data} </TableCell>
+                                        else
+                                        return null;
+                                    })
+                                }
+                                {
+
+                                    props.actions && <TableCell >  
+<div style={{display:"flex"}}>                                           
+    <Tooltip title="Configure">
+    <Button className={classes.button} disabled={row.status!=="connected"} onClick={(e: any) =>{ e.preventDefault(); e.stopPropagation(); props.navigate && props.navigate("configuration", row.simulatorId ? row.simulatorId : row.name)}}>C</Button>
+    </Tooltip>
+    <Tooltip title="Fault">
+    <Button className={classes.button} onClick={(e: any) =>{ e.preventDefault(); e.stopPropagation(); props.navigate && props.navigate("fault", row.simulatorId ? row.simulatorId : row.name)}}>F</Button>
+    </Tooltip>
+    </div> 
+    </TableCell>
+    
+                                }
+                            </TableRow>)
+                    })
+                    }
+
+                </TableBody>
+            </Table>
+       
+        </Paper>
+    );
+
+}
+
+export default DenseTable;
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/handlers/linkCalculationAppRootHandler.ts b/sdnr/wt/odlux/apps/linkCalculationApp/src/handlers/linkCalculationAppRootHandler.ts
new file mode 100644
index 0000000..00dd48d
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/handlers/linkCalculationAppRootHandler.ts
@@ -0,0 +1,115 @@
+/**
+* ============LICENSE_START========================================================================
+* ONAP : ccsdk feature sdnr wt odlux
+* =================================================================================================
+* Copyright (C) 2020 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 { UpdateLinkIdAction, UpdateFrequencyAction , UpdateLatLonAction, UpdateRainAttAction, UpdateRainValAction, updateHideForm, UpdateFslCalculation, UpdateSiteAction, UpdateDistanceAction, isCalculationServerReachableAction} from '../actions/commonLinkCalculationActions';
+
+declare module '../../../../framework/src/store/applicationStore' {
+  interface IApplicationStoreState {
+    linkCalculation: ICalculationsState;
+  }
+}
+
+type ICalculationsState = {
+  calculations:ILinkCalculationAppStateState
+}
+
+export type ILinkCalculationAppStateState= {
+  linkId: string | null,
+  frequency: number,
+  formView:boolean,
+  fsl:number,
+  distance:number,
+  Lat1: number,
+  Lon1: number,
+  Lat2: number, 
+  Lon2: number,
+  rainVal : number,
+  rainAtt : number,
+  siteA: any,
+  siteB: any,
+  reachable: boolean
+}
+
+const initialState: ILinkCalculationAppStateState ={
+  linkId: null,
+  frequency: 0,
+  Lat1: 0,
+  Lon1: 0,
+  Lat2: 0,
+  Lon2: 0,
+  formView : false,
+  fsl:0,
+  distance:0,
+  siteA : '',
+  siteB: '',
+  rainVal : 0,
+  rainAtt: 0,
+  reachable : true
+}
+
+
+
+export const LinkCalculationHandler: IActionHandler<ILinkCalculationAppStateState> = (state=initialState, action) => {
+    
+  if(action instanceof UpdateLinkIdAction){
+      state = Object.assign({}, state, {linkId:action.linkId})
+  } 
+  else if(action instanceof updateHideForm){
+
+    state = Object.assign({}, state, {formView:action.formView})
+  }
+  else if (action instanceof UpdateDistanceAction){
+    state = Object.assign({}, state, {distance:action.distance})
+  }
+  else if (action instanceof UpdateFrequencyAction){
+    state = Object.assign({}, state, {frequency:action.frequency})
+}
+  else if (action instanceof UpdateFslCalculation){
+  state = Object.assign({}, state, {fsl:action.fsl})
+  }
+  else if (action instanceof UpdateLatLonAction){
+    state = Object.assign({}, state, {Lat1:action.Lat1, Lon1:action.Lon1, Lat2:action.Lat2, Lon2:action.Lon2})
+  }
+  else if (action instanceof UpdateRainAttAction){
+    state = Object.assign({}, state, {rainAtt:action.rainAtt})
+  }
+  else if (action instanceof UpdateRainValAction){
+    state = Object.assign({}, state, {rainVal:action.rainVal})
+  }
+  else if (action instanceof UpdateSiteAction){
+    state = Object.assign({}, state, {siteA:action.siteA, siteB:action.siteB})
+  }
+  else if(action instanceof isCalculationServerReachableAction){
+    state = Object.assign({}, state, { reachable: action.reachable });
+}
+  return state
+}
+
+const actionHandlers = {
+  calculations: LinkCalculationHandler
+}
+
+export const LinkCalculationAppRootHandler = combineActionHandler<ICalculationsState>(actionHandlers); 
+export default LinkCalculationAppRootHandler;
+
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/index.html b/sdnr/wt/odlux/apps/linkCalculationApp/src/index.html
new file mode 100644
index 0000000..c1cb3f9
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/index.html
@@ -0,0 +1,27 @@
+<!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>Link Calculation App</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", "networkMapApp", "linkCalculationApp"], function (app, connectApp, networkMapApp, linkCalculationApp) {
+      connectApp.register();
+      linkCalculationApp.register();
+      networkMapApp.register();
+      app("./app.tsx").runApplication();
+    });
+  </script>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/pluginLinkCalculation.tsx b/sdnr/wt/odlux/apps/linkCalculationApp/src/pluginLinkCalculation.tsx
new file mode 100644
index 0000000..fc72f5a
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/pluginLinkCalculation.tsx
@@ -0,0 +1,148 @@
+/**
+* ============LICENSE_START========================================================================
+* ONAP : ccsdk feature sdnr wt odlux
+* =================================================================================================
+* Copyright (C) 2020 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 { withRouter, RouteComponentProps, Route, Switch, Redirect } from 'react-router-dom';
+
+import { faBookOpen } from '@fortawesome/free-solid-svg-icons'; // select app icon
+import applicationManager from '../../../framework/src/services/applicationManager';
+
+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 } from "./actions/commonLinkCalculationActions";
+
+
+let currentLinkId: string | null = null;
+let lastUrl: string = "/linkCalculation";
+
+const mapProps = (state: IApplicationStoreState) => ({
+});
+
+const mapDisp = (dispatcher: IDispatcher) => ({
+  updateLinkId: (mountId: string) => dispatcher.dispatch(new UpdateLinkIdAction(mountId)),
+
+  updateSiteName: (siteNameA?:any, siteNameB?:any)=>{
+    dispatcher.dispatch(new UpdateSiteAction(siteNameA, siteNameB))
+  },
+  updateDistance :(distance:number) =>{
+    dispatcher.dispatch(new UpdateDistanceAction(distance))
+  },
+  updateLatLon : (Lat1:number, Lon1:number, Lat2:number, Lon2:number)=> {
+
+    dispatcher.dispatch(new UpdateLatLonAction(Lat1, Lon1, Lat2, Lon2))
+    dispatcher.dispatch(new updateHideForm (true))
+  },
+});
+
+
+const LinkCalculationRouteAdapter = connect(mapProps, mapDisp)((props: RouteComponentProps<{ mountId?: string }> & Connect<typeof mapProps, typeof mapDisp>) => {
+  let linkId: string = "";
+
+  // called when component finshed mounting
+  React.useEffect(() => {
+
+    lastUrl = props.location.pathname;
+    linkId = getLinkId(lastUrl);
+
+    const data= props.location.search
+
+    
+
+    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 distance = data.split('&')[8].split('=')[1]
+
+
+    props.updateSiteName(String(siteNameA), String(siteNameB))
+    props.updateDistance(Number(distance))
+
+
+    props.updateLatLon(Number(lat1),Number(lon1),Number(lat2),Number(lon2))
+    
+    }
+    
+
+    if (currentLinkId !== linkId) { // new element is loaded
+      currentLinkId = linkId;
+      props.updateLinkId(currentLinkId);
+    } 
+  }, []);
+
+  // called when component gets updated
+  React.useEffect(() => {
+
+    lastUrl = props.location.pathname;
+    linkId = getLinkId(lastUrl);
+
+    if (currentLinkId !== linkId) {
+      currentLinkId = linkId;
+      props.updateLinkId(currentLinkId);
+    }
+  });
+
+  const getLinkId = (lastUrl: string) => {
+    let index = lastUrl.lastIndexOf("linkCalculation/");
+    if (index >= 0) {
+      linkId = lastUrl.substr(index+16);
+    } else {
+      linkId = "";
+    }
+
+    return linkId;
+  }
+
+  
+  return (
+    <LinkCalculation />
+  );
+});
+
+const App = withRouter((props: RouteComponentProps) => {
+  props.history.action = "POP";
+  return (
+    <Switch>
+      <Route path={`${props.match.path}/:linkId`} component={LinkCalculationRouteAdapter} />
+      <Route path={`${props.match.path}`} component={LinkCalculationRouteAdapter} />
+      <Redirect to={`${props.match.path}`} />
+    </Switch>
+  )
+});
+
+export function register() {
+  applicationManager.registerApplication({
+    name: "linkCalculation",
+    icon: faBookOpen,
+    rootActionHandler: LinkCalculationAppRootHandler,
+    rootComponent: App,
+    menuEntry: "Link Calculation"
+  });
+}
+
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src/views/linkCalculationComponent.tsx b/sdnr/wt/odlux/apps/linkCalculationApp/src/views/linkCalculationComponent.tsx
new file mode 100644
index 0000000..97219b6
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/src/views/linkCalculationComponent.tsx
@@ -0,0 +1,246 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2020 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 { Connect, connect, IDispatcher } from '../../../../framework/src/flux/connect';
+import { MaterialTable, MaterialTableCtorType } from '../../../../framework/src/components/material-table';
+import { TextField, Tabs, Tab, Typography, AppBar, Button, Tooltip } from '@material-ui/core';
+import DenseTable from '../components/denseTable'
+
+import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore";
+import { UpdateFrequencyAction, UpdateLatLonAction, UpdateRainAttAction, UpdateRainValAction, UpdateFslCalculation, isCalculationServerReachableAction } from "../actions/commonLinkCalculationActions";
+import { faPlaneArrival } from "@fortawesome/free-solid-svg-icons";
+
+const mapProps = (state: IApplicationStoreState) => ({
+  linkId: state.linkCalculation.calculations.linkId,
+  frequency: state.linkCalculation.calculations.frequency,
+  lat1: state.linkCalculation.calculations.Lat1,
+  lon1: state.linkCalculation.calculations.Lon1,
+  lat2: state.linkCalculation.calculations.Lat2,
+  lon2: state.linkCalculation.calculations.Lon2,
+  rainAtt: state.linkCalculation.calculations.rainAtt,
+  rainVal: state.linkCalculation.calculations.rainVal,
+  formView: state.linkCalculation.calculations.formView,
+  fsl:state.linkCalculation.calculations.fsl,
+  siteA: state.linkCalculation.calculations.siteA,
+  siteB: state.linkCalculation.calculations.siteB,
+  distance: state.linkCalculation.calculations.distance,
+  reachable :state.linkCalculation.calculations.reachable
+});
+
+const BASE_URL="/topology/services"
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+
+  updateFrequency: (frequency: number) => {
+    dispatcher.dispatch(new UpdateFrequencyAction(frequency))
+
+  },
+  updateLatLon: (Lat1: number, Lon1: number, Lat2: number, Lon2: number) => {
+
+    dispatcher.dispatch(new UpdateLatLonAction(Lat1, Lon1, Lat2, Lon2))
+
+  },
+  
+  updateRainValue: (rainVal: number) => {
+    dispatcher.dispatch(new UpdateRainValAction(rainVal))
+  },
+
+  UpdateRainAtt: (rainAtt: number) => {
+    dispatcher.dispatch(new UpdateRainAttAction(rainAtt))
+  },
+
+  specificRain: (rainAtt: number) => {
+    dispatcher.dispatch(new UpdateRainAttAction(rainAtt))
+
+  },
+ 
+  FSL :(free:number)=> {
+    dispatcher.dispatch(new UpdateFslCalculation (free))
+  },
+
+  UpdateConectivity : (reachable:boolean) => {
+    dispatcher.dispatch (new isCalculationServerReachableAction (reachable))
+  }
+});
+
+class LinkCalculation extends React.Component<Connect<typeof mapProps, typeof mapDispatch>, { rainMethodDisplay: boolean }> {
+  constructor(props: any) {
+    super(props)
+    this.state = { rainMethodDisplay: true }
+  }
+
+  handleChange = (e: number) => {
+    this.props.updateFrequency(e)
+  }
+
+  updateLatLon = (e: any) => {
+    
+    if (e.target.id == 'Lat1') this.props.updateLatLon(e.target.value, this.props.lon1, this.props.lat2, this.props.lon2)
+    if (e.target.id == 'Lon1') this.props.updateLatLon(this.props.lat1, e.target.value, this.props.lat2, this.props.lon2)
+    if (e.target.id == 'Lat2') this.props.updateLatLon(this.props.lat1, this.props.lon1, e.target.value, this.props.lon2)
+    if (e.target.id == 'Lon2') this.props.updateLatLon(this.props.lat1, this.props.lon1, this.props.lat2, e.target.value)
+
+  }
+
+  LatLonToDMS = (value: number, isLon: boolean = false) => {
+    const absoluteValue = Math.abs(value);
+    const d = Math.floor(absoluteValue);
+    const m = Math.floor((absoluteValue - d) * 60);
+    const s = (absoluteValue - d - m / 60) * 3600;
+    const dms = `${d}° ${m}' ${s.toFixed(2)}"`
+
+    const sign = Math.sign(value);
+
+    if (isLon) {
+      return (sign === -1 || sign === -0) ? dms + " W" : dms + " E";
+    } else {
+      return (sign === -1 || sign === -0) ? dms + " S" : dms + " N";
+    }
+  }
+
+  calRain = (lat1: any, lon1: any, lat2: any, lon2: any, frequency: any) => {
+    fetch(BASE_URL+'/calculations/rain/' + lat1 + '/' + lon1 + '/' + lat2 + '/' + lon2 + '/' + frequency)
+      .then(res => res.json())
+      .then(result => { this.props.UpdateRainAtt(result.RainAtt) })
+  }
+
+
+  updateRainValue = (lat1: any, lon1: any, lat2: any, lon2: any) => {
+    fetch(BASE_URL+'/calculations/rain/' + lat1 + '/' + lon1 + '/' + lat2 + '/' + lon2)
+      .then(res => res.json())
+      .then(result => { this.props.updateRainValue(result.RainAtt) })
+  }
+
+
+  specificRain = (rainfall: number, frequency: number) => {
+    fetch(BASE_URL+'/calculations/rain/' + rainfall + '/' + frequency)
+      .then(res => res.json())
+      .then(result => { this.props.specificRain(result.RainAtt) })
+    }
+
+    FSL = (distance:number, frequency:number) => {
+      fetch(BASE_URL+'/calculations/FSL/' + distance + '/' + frequency)
+      .then(res=>res.json())
+      .then (result => {this.props.FSL(result.free)})
+    }
+
+  buttonHandler =() => {
+      this.FSL(this.props.distance, this.props.frequency)
+
+      if (this.state.rainMethodDisplay === true){
+
+        this.specificRain(this.props.rainVal, this.props.frequency); 
+      }
+      else {
+        this.calRain(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2, this.props.frequency);
+        this.updateRainValue(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2)
+      }
+  }
+
+  componentDidMount = () => {
+    fetch (BASE_URL+'/calculations/fsl/0/0')
+    .then(res => {if (res.ok) {this.props.reachable===false && this.props.UpdateConectivity(true)}else {this.props.reachable===true && this.props.UpdateConectivity(false)} })
+    .catch (res => {this.props.reachable===true && this.props.UpdateConectivity(false)} )
+  }
+  
+  render() {
+    console.log(this.props);
+    const data = [
+
+      { name: "Site Name", val1: this.props.siteA, val2: '', val3:  this.props.siteB},
+      { name: "Latitude", val1: this.props.lat1 && this.LatLonToDMS(this.props.lat1), val2:'', val3: this.props.lat2 && this.LatLonToDMS(this.props.lat2) },
+      { name: "Longitude", val1: this.props.lon1 && this.LatLonToDMS(this.props.lon1, true), val2:'', val3: this.props.lon2 && this.LatLonToDMS(this.props.lon2, true) },
+      { name: "Azimuth in °", val1: '', val2: '' , val3:''},
+      { name: "", val1: '', val2: '' , val3:''},
+      { name: "Distance (km)", val1: '', val2: (this.props.distance).toFixed(3) ,val3:'' },
+      {name: 'Polarization', val1:'', val2: <div><input type='checkbox' id='Horizontal' value ="Horizontal"></input>Horizontal<br />
+      <input type='checkbox' id='Vertical' value ="Vertical"></input>Vertical
+      </div>, val3:''},
+      {name : 'Frequency (GHz)', val1: '', val2:  <div> 
+      <select onChange={(e) => this.handleChange(Number(e.target.value))}>
+      <option value='' >Select Freq</option>
+      <option value='7' >7 GHz</option>
+      <option value='11' >11 GHz</option>
+      <option value='15' >15 GHz</option>
+      <option value='23' >23 GHz</option>
+      <option value='26' >26 GHz</option>
+      <option value='28' >28 GHz</option>
+      <option value='38' >38 GHz</option>
+      <option value='42' >42 GHz</option>
+      <option value='80' >80 GHz</option>
+        </select></div>,val3: ''},
+      {name: 'Free Space Loss (dB)' ,val1: '', val2: this.props.fsl,val3: ''},
+      {name:'Rain Model', val1:'', val2: <div>
+      <select onChange={e => { this.setState({ rainMethodDisplay: !this.state.rainMethodDisplay }) }} >
+        <option value='' >Select Rain Method</option>
+        <option value='itu' onSelect={e => { this.setState({ rainMethodDisplay: false }) }}>ITU-R P.837-7</option>
+        <option value='manual' onSelect={(e) => { this.updateRainValue(this.props.lat1, this.props.lon1, this.props.lat2, this.props.lon2) }}  >Specific Rain</option>
+      </select> </div>, val3:''},
+      {name: 'Rainfall Rate (mm/h)', val1: '', val2:<label>
+       <input type="number" style={{ width: 70, height: 15, fontSize: 14 }} onChange={(e) => { this.props.updateRainValue(Number(e.target.value)) }}
+        value={this.props.rainVal} disabled={this.state.rainMethodDisplay === false ? true : false}>
+      </input></label>, val3:''},
+      {name: 'Rain Loss (dB/km)', val1: '', val2: this.props.rainAtt, val3: ''},
+      {name: '', val1:'', val2:<button style={{color: '#222', fontFamily:'Arial', boxAlign: 'center', display:'inline-block', insetInlineStart: '20' }}
+      onClick = {(e) => this.buttonHandler()} >Calculate</button>, val3:'' }
+     
+    ];
+
+
+    return <div>
+      Link Calculation app. LinkId: {this.props.linkId} <br />
+
+      {!this.props.formView && <form>
+          <div>
+          
+            <br />Site A 
+            <br /> Site Id:
+                <label style={{ marginInlineStart: 20 }}> latitude
+                <input id='Lat1' type='number' onChange={(e: any) => this.updateLatLon(e)} />
+            </label>
+            <label style={{ marginInlineStart: 20 }}>longitude
+                <input id='Lon1' type='number' onChange={(e: any) => this.updateLatLon(e)} />
+            </label><br /><br />
+
+          </div>
+          <div> <br />Site B<br /> Site Id:
+                <label style={{ marginInlineStart: 20 }}> latitude
+                <input id='Lat2' type='number' onChange={(e: any) => this.updateLatLon(e)} />
+            </label>
+            <label style={{ marginInlineStart: 20 }}>longitude
+                <input id='Lon2' type='number' onChange={(e: any) => this.updateLatLon(e)} />
+            </label>
+            <br />
+          </div>
+        </form>
+        }
+      
+        <DenseTable height={600} width={1300} hover={true} headers={["", "Site A","", "Site B"]} data={data}> </DenseTable>
+
+          
+
+      
+    </div>
+
+  }
+
+
+}
+
+export default connect(mapProps, mapDispatch)(LinkCalculation);
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java b/sdnr/wt/odlux/apps/linkCalculationApp/src2/main/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/MyOdluxBundle.java
new file mode 100644
index 0000000..43b072c
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/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/linkCalculationApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml b/sdnr/wt/odlux/apps/linkCalculationApp/src2/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644
index 0000000..8eb652e
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/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="linkCalculationApp"/>
+        <property name="index" value="120"/>
+    </bean>
+</blueprint>
\ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/linkCalculationApp/src2/test/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/test/TestBundleRes.java b/sdnr/wt/odlux/apps/linkCalculationApp/src2/test/java/org/onap/ccsdk/features/sdnr/wt/odlux/bundles/test/TestBundleRes.java
new file mode 100644
index 0000000..c319bb1
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/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/linkCalculationApp/src2/test/resources/test.js b/sdnr/wt/odlux/apps/linkCalculationApp/src2/test/resources/test.js
new file mode 100644
index 0000000..b47fdc3
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/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/linkCalculationApp/tsconfig.json b/sdnr/wt/odlux/apps/linkCalculationApp/tsconfig.json
new file mode 100644
index 0000000..a66b5d8
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/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/linkCalculationApp/webpack.config.js b/sdnr/wt/odlux/apps/linkCalculationApp/webpack.config.js
new file mode 100644
index 0000000..4f2bd2e
--- /dev/null
+++ b/sdnr/wt/odlux/apps/linkCalculationApp/webpack.config.js
@@ -0,0 +1,159 @@
+/**
+ * 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: {
+      linkCalculationApp: ["./pluginLinkCalculation.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"
+        }]
+      }]
+    },
+
+    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: {
+        "/oauth2/": {
+          target: "http://10.20.6.29:8181",
+          secure: false
+        },
+        "/database/": {
+          target: "http://10.20.6.29:8181",
+          secure: false
+        },
+        "/restconf/": {
+          target: "http://10.20.6.29:8181",
+          secure: false
+        },
+        "/topology/": {
+          target: "http://localhost:3001",
+          secure: false
+        },
+        "/help/": {
+          target: "http://10.20.6.29:8181",
+          secure: false
+        },
+        "/websocket/": {
+          target: "http://10.20.6.29:8181",
+          ws: true,
+          changeOrigin: true,
+          secure: false
+        }
+      }
+
+    }
+  }];
+}
diff --git a/sdnr/wt/odlux/apps/maintenanceApp/pom.xml b/sdnr/wt/odlux/apps/maintenanceApp/pom.xml
index 874d17c..e66404c 100644
--- a/sdnr/wt/odlux/apps/maintenanceApp/pom.xml
+++ b/sdnr/wt/odlux/apps/maintenanceApp/pom.xml
@@ -43,6 +43,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/sdnr/wt/odlux/apps/mediatorApp/pom.xml b/sdnr/wt/odlux/apps/mediatorApp/pom.xml
index 21d5d61..6accabe 100644
--- a/sdnr/wt/odlux/apps/mediatorApp/pom.xml
+++ b/sdnr/wt/odlux/apps/mediatorApp/pom.xml
@@ -43,6 +43,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/sdnr/wt/odlux/apps/minimumApp/pom.xml b/sdnr/wt/odlux/apps/minimumApp/pom.xml
index 55bdf97..8135426 100644
--- a/sdnr/wt/odlux/apps/minimumApp/pom.xml
+++ b/sdnr/wt/odlux/apps/minimumApp/pom.xml
@@ -43,6 +43,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/pom.xml b/sdnr/wt/odlux/apps/performanceHistoryApp/pom.xml
index 819c742..5ace21f 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/pom.xml
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/pom.xml
@@ -43,6 +43,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/sdnr/wt/odlux/core/model/pom.xml b/sdnr/wt/odlux/core/model/pom.xml
index 39a09ff..895734f 100644
--- a/sdnr/wt/odlux/core/model/pom.xml
+++ b/sdnr/wt/odlux/core/model/pom.xml
@@ -43,6 +43,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>org.osgi</groupId>
diff --git a/sdnr/wt/odlux/core/provider/pom.xml b/sdnr/wt/odlux/core/provider/pom.xml
index afe14f4..70cd244 100644
--- a/sdnr/wt/odlux/core/provider/pom.xml
+++ b/sdnr/wt/odlux/core/provider/pom.xml
@@ -43,6 +43,11 @@
         </license>
     </licenses>
 
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <checkstyle.skip>true</checkstyle.skip>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
@@ -59,6 +64,7 @@
             <artifactId>jetty-server</artifactId>
             <scope>test</scope>
         </dependency>
+
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
diff --git a/sdnr/wt/odlux/framework/pom.xml b/sdnr/wt/odlux/framework/pom.xml
index db42ef1..a7c81eb 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>57.3e1d5cf(20/08/11)</buildno>
+        <buildno>62.ad364be(20/08/21)</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/components/material-table/index.tsx b/sdnr/wt/odlux/framework/src/components/material-table/index.tsx
index 3dfbe0b..c5be819 100644
--- a/sdnr/wt/odlux/framework/src/components/material-table/index.tsx
+++ b/sdnr/wt/odlux/framework/src/components/material-table/index.tsx
@@ -234,7 +234,7 @@
                       }}
                       role="checkbox"
                       aria-checked={isSelected}
-                      aria-label={`${(this.props.tableId ? this.props.tableId : 'table')}-row-${(index + 1)}`}
+                      aria-label={`${(this.props.tableId ? this.props.tableId : 'table')}-row`}
                       tabIndex={-1}
                       key={entryId}
                       selected={isSelected}
@@ -284,10 +284,10 @@
           rowsPerPage={rowsPerPage}
           page={page}
           backIconButtonProps={{
-            'aria-label': 'Previous Page',
+            'aria-label': 'previous-page',
           }}
           nextIconButtonProps={{
-            'aria-label': 'Next Page',
+            'aria-label': 'next-page',
           }}
           onChangePage={this.onHandleChangePage}
           onChangeRowsPerPage={this.onHandleChangeRowsPerPage}
diff --git a/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx b/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx
index 464350a..76f778e 100644
--- a/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx
+++ b/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx
@@ -74,11 +74,11 @@
                 ? null
                 : (col.type === ColumnType.boolean)
                   ? <Select className={classes.input} aria-label={col.title ? (col.title as string).toLowerCase() + ' filter' : `${ind + 1}-filter`} value={filter[col.property] !== undefined ? filter[col.property] : ''} onChange={this.createFilterHandler(col.property)} inputProps={{ name: `${col.property}-bool`, id: `${col.property}-bool` }} >
-                    <MenuItem value={undefined} >
+                    <MenuItem value={undefined} aria-label="none-value" >
                       <em>None</em>
                     </MenuItem>
-                    <MenuItem value={true as any as string}>{col.labels ? col.labels["true"] : "true"}</MenuItem>
-                    <MenuItem value={false as any as string}>{col.labels ? col.labels["false"] : "false"}</MenuItem>
+                    <MenuItem aria-label="true-value" value={true as any as string}>{col.labels ? col.labels["true"] : "true"}</MenuItem>
+                    <MenuItem aria-label="false-value" value={false as any as string}>{col.labels ? col.labels["false"] : "false"}</MenuItem>
                   </Select>
                   : <Input className={classes.input} inputProps={{ 'aria-label': col.title ? (col.title as string).toLowerCase() + ' filter' : `${ind + 1}-filter` }} value={filter[col.property] || ''} onChange={this.createFilterHandler(col.property)} />}
             </TableCell>
diff --git a/sdnr/wt/odlux/framework/src/components/material-ui/listItemLink.tsx b/sdnr/wt/odlux/framework/src/components/material-ui/listItemLink.tsx
index 1a7e58f..23bad66 100644
--- a/sdnr/wt/odlux/framework/src/components/material-ui/listItemLink.tsx
+++ b/sdnr/wt/odlux/framework/src/components/material-ui/listItemLink.tsx
@@ -1,20 +1,20 @@
-/**
- * ============LICENSE_START========================================================================
- * ONAP : ccsdk feature sdnr wt odlux
- * =================================================================================================
- * 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==========================================================================
- */
+/**

+ * ============LICENSE_START========================================================================

+ * ONAP : ccsdk feature sdnr wt odlux

+ * =================================================================================================

+ * 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==========================================================================

+ */

 import * as React from 'react';

 import { NavLink, Link, Route } from 'react-router-dom';

 

@@ -50,7 +50,7 @@
             : null

           }

         { typeof Primary === 'string'

-          ? <ListItemText primary={ Primary } style={{ padding: 0 }} /> 

+          ? <ListItemText aria-label={"link-to-"+Primary.toLowerCase()} primary={ Primary } style={{ padding: 0 }} /> 

           : <Primary />

           }

         </ListItem>

diff --git a/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx b/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx
index 620abd7..790677a 100644
--- a/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx
+++ b/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx
@@ -120,6 +120,11 @@
     }

   })

 

+  React.useEffect(()=>{

+    // trigger a resize if menu changed in case elements have to re-arrange

+    window.dispatchEvent(new Event('menu-resized'));

+  }, [isOpen])

+

   return (

     <Drawer

       variant="permanent"

diff --git a/sdnr/wt/odlux/framework/src/components/titleBar.tsx b/sdnr/wt/odlux/framework/src/components/titleBar.tsx
index 7168ff4..49c0966 100644
--- a/sdnr/wt/odlux/framework/src/components/titleBar.tsx
+++ b/sdnr/wt/odlux/framework/src/components/titleBar.tsx
@@ -101,8 +101,8 @@
     // create notificationInfo element

     const notificationInfo = state.framework.applicationState.isWebsocketAvailable != undefined ?

       (state.framework.applicationState.isWebsocketAvailable ?

-        <Typography variant="body1" className={classes.notificationInfo}>Notifications <FontAwesomeIcon className={classes.connected} icon={faDotCircle} />  |</Typography> : <Typography variant="body1" className={classes.notificationInfo}>Notifications <FontAwesomeIcon className={classes.notConnected} icon={faBan} /> |</Typography>)

-      : <Typography variant="body1" className={classes.notificationInfo}>Notifications N/A |</Typography>;

+        <Typography aria-label="notifications-are-active" variant="body1" className={classes.notificationInfo}>Notifications <FontAwesomeIcon className={classes.connected} icon={faDotCircle} />  |</Typography> : <Typography aria-label="notifications-are-inactive" variant="body1" className={classes.notificationInfo}>Notifications <FontAwesomeIcon className={classes.notConnected} icon={faBan} /> |</Typography>)

+      : <Typography variant="body1" aria-label="notifications-are-not-available" className={classes.notificationInfo}>Notifications N/A |</Typography>;

 

 

     // add notificationInfo element before help

diff --git a/sdnr/wt/odlux/framework/src/services/notificationService.ts b/sdnr/wt/odlux/framework/src/services/notificationService.ts
index c90da09..4bcc05c 100644
--- a/sdnr/wt/odlux/framework/src/services/notificationService.ts
+++ b/sdnr/wt/odlux/framework/src/services/notificationService.ts
@@ -1,193 +1,193 @@
-/**

- * ============LICENSE_START========================================================================

- * ONAP : ccsdk feature sdnr wt odlux

- * =================================================================================================

- * 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==========================================================================

- */

-import * as X2JS from 'x2js';

-import { ApplicationStore } from '../store/applicationStore';

-import { SetWebsocketAction } from '../actions/websocketAction';

-

-const socketUrl = [location.protocol === 'https:' ? 'wss://' : 'ws://', 'admin', ':', 'admin', '@', location.hostname, ':', location.port, '/websocket'].join('');

-const subscriptions: { [scope: string]: SubscriptionCallback[] } = {};

-let socketReady: Promise<WebSocket>;

-let userLoggedOut = false;

-let wasWebsocketConnectionEstablished: undefined | boolean;

-let applicationStore: ApplicationStore | null;

-

-

-export interface IFormatedMessage {

-  notifType: string | null;

-  time: string;

-}

-

-export type SubscriptionCallback<TMessage extends IFormatedMessage = IFormatedMessage> = (msg: TMessage) => void;

-

-function formatData(event: MessageEvent): IFormatedMessage | undefined {

-

-  var x2js = new X2JS();

-  var jsonObj: { [key: string]: IFormatedMessage } = x2js.xml2js(event.data);

-  if (jsonObj && typeof (jsonObj) === 'object') {

-

-    const notifType = Object.keys(jsonObj)[0];

-    const formated = jsonObj[notifType];

-    formated.notifType = notifType;

-    formated.time = new Date().toISOString();

-    return formated;

-  }

-  return undefined;

-

-}

-

-export function subscribe<TMessage extends IFormatedMessage = IFormatedMessage>(scope: string | string[], callback: SubscriptionCallback<TMessage>): boolean {

-  const scopes = scope instanceof Array ? scope : [scope];

-

-  // send all new scopes to subscribe

-  const newScopesToSubscribe: string[] = scopes.reduce((acc: string[], cur: string) => {

-    const currentCallbacks = subscriptions[cur];

-    if (currentCallbacks) {

-      if (!currentCallbacks.some(c => c === callback)) {

-        currentCallbacks.push(callback);

-      }

-    } else {

-      subscriptions[cur] = [callback];

-      acc.push(cur);

-    }

-    return acc;

-  }, []);

-

-  if (newScopesToSubscribe.length === 0) {

-    return true;

-  }

-

-  return true;

-}

-

-

-export function unsubscribe<TMessage extends IFormatedMessage = IFormatedMessage>(scope: string | string[], callback: SubscriptionCallback<TMessage>): Promise<boolean> {

-  return socketReady.then((notificationSocket) => {

-    const scopes = scope instanceof Array ? scope : [scope];

-    scopes.forEach(s => {

-      const callbacks = subscriptions[s];

-      const index = callbacks && callbacks.indexOf(callback);

-      if (index > -1) {

-        callbacks.splice(index, 1);

-      }

-      if (callbacks.length === 0) {

-        subscriptions[s] === undefined;

-      }

-    });

-

-    // send a subscription to all active scopes

-    const scopesToSubscribe = Object.keys(subscriptions);

-    if (notificationSocket.readyState === notificationSocket.OPEN) {

-      const data = {

-        'data': 'scopes',

-        'scopes': scopesToSubscribe

-      };

-      notificationSocket.send(JSON.stringify(data));

-      return true;

-    }

-    return false;

-  });

-}

-

-export const startNotificationService = (store: ApplicationStore) => {

-  applicationStore = store;

-}

-

-const connect = (): Promise<WebSocket> => {

-  return new Promise((resolve, reject) => {

-    const notificationSocket = new WebSocket(socketUrl);

-

-    notificationSocket.onmessage = (event) => {

-      // process received event

-      if (typeof event.data === 'string') {

-        const formated = formatData(event);

-        if (formated && formated.notifType) {

-          const callbacks = subscriptions[formated.notifType];

-          if (callbacks) {

-            callbacks.forEach(cb => {

-              // ensure all callbacks will be called

-              try {

-                return cb(formated);

-              } catch (reason) {

-                console.error(reason);

-              }

-            });

-          }

-        }

-      }

-    };

-

-    notificationSocket.onerror = function (error) {

-      console.log("Socket error:");

-      console.log(error);

-      reject("Socket error: " + error);

-      if (applicationStore) {

-        applicationStore.dispatch(new SetWebsocketAction(false));

-      }

-    };

-

-    notificationSocket.onopen = function (event) {

-      if (applicationStore) {

-        applicationStore.dispatch(new SetWebsocketAction(true));

-      }

-      console.log("Socket connection opened.");

-      resolve(notificationSocket);

-

-      // send a subscription to all active scopes

-      const scopesToSubscribe = Object.keys(subscriptions);

-      if (notificationSocket.readyState === notificationSocket.OPEN) {

-        const data = {

-          'data': 'scopes',

-          'scopes': scopesToSubscribe

-        };

-        notificationSocket.send(JSON.stringify(data));

-      };

-    };

-

-    notificationSocket.onclose = function (event) {

-      console.log("socket connection closed");

-      if (applicationStore) {

-        applicationStore.dispatch(new SetWebsocketAction(false));

-      }

-      if (!userLoggedOut) {

-        socketReady = connect();

-      }

-    };

-  });

-}

-

-

-

-

-export const startWebsocketSession = () => {

-  socketReady = connect();

-  userLoggedOut = false;

-}

-

-export const endWebsocketSession = () => {

-  if (socketReady) {

-    socketReady.then(websocket => {

-      websocket.close();

-      userLoggedOut = true;

-    });

-  }

-

-}

-

-

-

-

+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * 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==========================================================================
+ */
+import * as X2JS from 'x2js';
+import { ApplicationStore } from '../store/applicationStore';
+import { SetWebsocketAction } from '../actions/websocketAction';
+
+const socketUrl = [location.protocol === 'https:' ? 'wss://' : 'ws://', 'admin', ':', 'admin', '@', location.hostname, ':', location.port, '/websocket'].join('');
+const subscriptions: { [scope: string]: SubscriptionCallback[] } = {};
+let socketReady: Promise<WebSocket>;
+let userLoggedOut = false;
+let wasWebsocketConnectionEstablished: undefined | boolean;
+let applicationStore: ApplicationStore | null;
+
+
+export interface IFormatedMessage {
+  notifType: string | null;
+  time: string;
+}
+
+export type SubscriptionCallback<TMessage extends IFormatedMessage = IFormatedMessage> = (msg: TMessage) => void;
+
+function formatData(event: MessageEvent): IFormatedMessage | undefined {
+
+  var x2js = new X2JS();
+  var jsonObj: { [key: string]: IFormatedMessage } = x2js.xml2js(event.data);
+  if (jsonObj && typeof (jsonObj) === 'object') {
+
+    const notifType = Object.keys(jsonObj)[0];
+    const formated = jsonObj[notifType];
+    formated.notifType = notifType;
+    formated.time = new Date().toISOString();
+    return formated;
+  }
+  return undefined;
+
+}
+
+export function subscribe<TMessage extends IFormatedMessage = IFormatedMessage>(scope: string | string[], callback: SubscriptionCallback<TMessage>): boolean {
+  const scopes = scope instanceof Array ? scope : [scope];
+
+  // send all new scopes to subscribe
+  const newScopesToSubscribe: string[] = scopes.reduce((acc: string[], cur: string) => {
+    const currentCallbacks = subscriptions[cur];
+    if (currentCallbacks) {
+      if (!currentCallbacks.some(c => c === callback)) {
+        currentCallbacks.push(callback);
+      }
+    } else {
+      subscriptions[cur] = [callback];
+      acc.push(cur);
+    }
+    return acc;
+  }, []);
+
+  if (newScopesToSubscribe.length === 0) {
+    return true;
+  }
+
+  return true;
+}
+
+
+export function unsubscribe<TMessage extends IFormatedMessage = IFormatedMessage>(scope: string | string[], callback: SubscriptionCallback<TMessage>): Promise<boolean> {
+  return socketReady.then((notificationSocket) => {
+    const scopes = scope instanceof Array ? scope : [scope];
+    scopes.forEach(s => {
+      const callbacks = subscriptions[s];
+      const index = callbacks && callbacks.indexOf(callback);
+      if (index > -1) {
+        callbacks.splice(index, 1);
+      }
+      if (callbacks.length === 0) {
+        subscriptions[s] === undefined;
+      }
+    });
+
+    // send a subscription to all active scopes
+    const scopesToSubscribe = Object.keys(subscriptions);
+    if (notificationSocket.readyState === notificationSocket.OPEN) {
+      const data = {
+        'data': 'scopes',
+        'scopes': scopesToSubscribe
+      };
+      notificationSocket.send(JSON.stringify(data));
+      return true;
+    }
+    return false;
+  });
+}
+
+export const startNotificationService = (store: ApplicationStore) => {
+  applicationStore = store;
+}
+
+const connect = (): Promise<WebSocket> => {
+  return new Promise((resolve, reject) => {
+    const notificationSocket = new WebSocket(socketUrl);
+
+    notificationSocket.onmessage = (event) => {
+      // process received event
+      if (typeof event.data === 'string') {
+        const formated = formatData(event);
+        if (formated && formated.notifType) {
+          const callbacks = subscriptions[formated.notifType];
+          if (callbacks) {
+            callbacks.forEach(cb => {
+              // ensure all callbacks will be called
+              try {
+                return cb(formated);
+              } catch (reason) {
+                console.error(reason);
+              }
+            });
+          }
+        }
+      }
+    };
+
+    notificationSocket.onerror = function (error) {
+      console.log("Socket error:");
+      console.log(error);
+      reject("Socket error: " + error);
+      if (applicationStore) {
+        applicationStore.dispatch(new SetWebsocketAction(false));
+      }
+    };
+
+    notificationSocket.onopen = function (event) {
+      if (applicationStore) {
+        applicationStore.dispatch(new SetWebsocketAction(true));
+      }
+      console.log("Socket connection opened.");
+      resolve(notificationSocket);
+
+      // send a subscription to all active scopes
+      const scopesToSubscribe = Object.keys(subscriptions);
+      if (notificationSocket.readyState === notificationSocket.OPEN) {
+        const data = {
+          'data': 'scopes',
+          'scopes': scopesToSubscribe
+        };
+        notificationSocket.send(JSON.stringify(data));
+      };
+    };
+
+    notificationSocket.onclose = function (event) {
+      console.log("socket connection closed");
+      if (applicationStore) {
+        applicationStore.dispatch(new SetWebsocketAction(false));
+      }
+      if (!userLoggedOut) {
+        socketReady = connect();
+      }
+    };
+  });
+}
+
+
+
+
+export const startWebsocketSession = () => {
+  socketReady = connect();
+  userLoggedOut = false;
+}
+
+export const endWebsocketSession = () => {
+  if (socketReady) {
+    socketReady.then(websocket => {
+      websocket.close();
+      userLoggedOut = true;
+    });
+  }
+
+}
+
+
+
+
diff --git a/sdnr/wt/odlux/framework/src/views/about.tsx b/sdnr/wt/odlux/framework/src/views/about.tsx
index c4a5488..f97d6ff 100644
--- a/sdnr/wt/odlux/framework/src/views/about.tsx
+++ b/sdnr/wt/odlux/framework/src/views/about.tsx
@@ -40,11 +40,23 @@
     this.textarea = React.createRef();
     this.loadAboutContent();
   }
+  private getMarkOdluxVersionMarkdownTable(data:{version:string,build:string}|null|undefined):string{
+    if(!data) {
+      return "";
+    }
+    return `| | |\n| --- | --- |\n| Version | ${data.version} |\n| Build timestamp | ${data.build}|`
+  }
   private loadAboutContent(): void {
-    requestRestExt<string>('/about').then((response) => {
+    const baseUri = window.location.pathname.substring(0,window.location.pathname.lastIndexOf("/")+1);
+    const p1 = requestRestExt<string>('/about');
+    const p2 = requestRestExt<{version:string,build:string}>(`${baseUri}version.json`);
+    Promise.all([p1,p2]).then((responses) => {
+      const response = responses[0];
+      const response2 = responses[1];    
       const content = response.status == 200 ? response.data : `${response.status} ${response.message}` || "Server error";
+      const content2 = `\n## ODLUX Version Info\n`+(response2.status == 200 ? this.getMarkOdluxVersionMarkdownTable(response2.data) : `${response2.status} ${response2.message}` || "ODLUX Server error");
       const loadedSucessfully = response.status == 200 ? true : false;
-      this.setState({ content: content || null, isContentLoadedSucessfully: loadedSucessfully });
+      this.setState({ content: (content + content2) || null, isContentLoadedSucessfully: loadedSucessfully });
     }).catch((error) => {
       this.setState({ content: error })
     })
diff --git a/sdnr/wt/odlux/framework/src/views/login.tsx b/sdnr/wt/odlux/framework/src/views/login.tsx
index 30b9c85..b06cf76 100644
--- a/sdnr/wt/odlux/framework/src/views/login.tsx
+++ b/sdnr/wt/odlux/framework/src/views/login.tsx
@@ -142,6 +142,7 @@
                 label="Remember me"
               />
               <Button
+                aria-label="login-button"
                 type="submit"
                 fullWidth
                 variant="contained"
diff --git a/sdnr/wt/odlux/framework/webpack.config.js b/sdnr/wt/odlux/framework/webpack.config.js
index c7ef72e..ad5b4cc 100644
--- a/sdnr/wt/odlux/framework/webpack.config.js
+++ b/sdnr/wt/odlux/framework/webpack.config.js
@@ -171,7 +171,11 @@
           new webpack.WatchIgnorePlugin([

             /css\.d\.ts$/,

             /less\.d\.ts$/

-          ])

+          ]),

+          new CopyWebpackPlugin([{

+            from: './assets/version.json',

+            to: './version.json'

+          }])

         ]

     ],

 

@@ -210,6 +214,10 @@
           target: "http://10.20.6.29:48181",

           secure: false

         },

+        "/about": {

+          target: "http://10.20.6.29:48181",

+          secure: false

+        },

         "/websocket": {

           target: "http://10.20.6.29:48181",

           ws: true,

diff --git a/sdnr/wt/odlux/installer/pom.xml b/sdnr/wt/odlux/installer/pom.xml
new file mode 100644
index 0000000..5ff2791
--- /dev/null
+++ b/sdnr/wt/odlux/installer/pom.xml
@@ -0,0 +1,207 @@
+<?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>odlparent-lite</artifactId>
+        <version>2.0.1-SNAPSHOT</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+    <artifactId>sdnr-wt-odlux-installer</artifactId>
+    <version>1.0.1-SNAPSHOT</version>
+    <packaging>pom</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>
+        <application.name>sdnr-wt-odlux-installer</application.name>
+        <include.transitive.dependencies>false</include.transitive.dependencies>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>maven-repo-zip</id>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <phase>package</phase>
+                        <configuration>
+                            <attach>true</attach>
+                            <finalName>stage/${application.name}-${project.version}</finalName>
+                            <descriptors>
+                                <descriptor>src/assembly/assemble_mvnrepo_zip.xml</descriptor>
+                            </descriptors>
+                            <appendAssemblyId>true</appendAssemblyId>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>unpack features</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <includes>odlux/**</includes>
+                            <outputDirectory>${project.build.directory}/assembly</outputDirectory>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>sdnr-wt-odlux-framework</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                </artifactItem>
+                                <!-- connectApp -->
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>sdnr-wt-odlux-app-connectApp</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                </artifactItem>
+                                <!-- eventLogApp -->
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>sdnr-wt-odlux-app-eventLogApp</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                </artifactItem>
+                                <!-- helpApp -->
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>sdnr-wt-odlux-app-helpApp</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                </artifactItem>
+                                <!-- maintenanceApp -->
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>sdnr-wt-odlux-app-maintenanceApp</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                </artifactItem>
+                                <!-- minimumApp -->
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>sdnr-wt-odlux-app-minimumApp</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                </artifactItem>
+                                <!-- configurationApp -->
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>sdnr-wt-odlux-app-configurationApp</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                </artifactItem>
+                                <!-- demoApp -->
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>sdnr-wt-odlux-app-demoApp</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                </artifactItem>
+                                <!-- faultApp -->
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>sdnr-wt-odlux-app-faultApp</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                </artifactItem>
+                                 <!-- linkCalculationApp-->
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>sdnr-wt-odlux-app-linkCalculationApp</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                </artifactItem>
+                                <!-- inventoryApp -->
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>sdnr-wt-odlux-app-inventoryApp</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                </artifactItem>
+                                <!-- mediatorApp -->
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>sdnr-wt-odlux-app-mediatorApp</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                </artifactItem>
+                                <!-- performanceHistoryApp -->
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>sdnr-wt-odlux-app-performanceHistoryApp</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                </artifactItem>
+                                <!-- helpserver resources -->
+                                <artifactItem>
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>sdnr-wt-helpserver-provider</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                    <includes>help/**</includes>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/sdnr/wt/odlux/installer/src/assembly/assemble_mvnrepo_zip.xml b/sdnr/wt/odlux/installer/src/assembly/assemble_mvnrepo_zip.xml
new file mode 100644
index 0000000..dfe5060
--- /dev/null
+++ b/sdnr/wt/odlux/installer/src/assembly/assemble_mvnrepo_zip.xml
@@ -0,0 +1,47 @@
+<!--
+  ~ ============LICENSE_START=======================================================
+  ~ ONAP : ccsdk features
+  ~ ================================================================================
+  ~ Copyright (C) 2017-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=======================================================
+  ~
+  -->
+
+<!-- Defines how we build the .zip file which is our distribution. -->
+
+<assembly
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+    <id>repo</id>
+    <formats>
+        <format>zip</format>
+    </formats>
+
+    <!--  we want "system" and related files right at the root level
+          as this file is suppose to be unzip on top of a karaf
+          distro. -->
+    <includeBaseDirectory>false</includeBaseDirectory>
+
+    <fileSets>
+        <fileSet>
+            <directory>target/assembly/</directory>
+            <outputDirectory>.</outputDirectory>
+            <excludes>
+            </excludes>
+        </fileSet>
+    </fileSets>
+
+</assembly>
diff --git a/sdnr/wt/odlux/pom.xml b/sdnr/wt/odlux/pom.xml
index 0aaf042..a822d3d 100644
--- a/sdnr/wt/odlux/pom.xml
+++ b/sdnr/wt/odlux/pom.xml
@@ -52,8 +52,10 @@
         <module>apps/performanceHistoryApp</module>
         <module>apps/eventLogApp</module>
         <module>apps/configurationApp</module>
+        <module>apps/linkCalculationApp</module>
         <module>apps/app-feature</module>
         <module>apps/app-installer</module>
+        <module>installer</module>
     </modules>
 
     <build>
diff --git a/sdnr/wt/odlux/yarn.lock b/sdnr/wt/odlux/yarn.lock
index 3db21a2..e71ad3f 100644
--- a/sdnr/wt/odlux/yarn.lock
+++ b/sdnr/wt/odlux/yarn.lock
@@ -1342,6 +1342,56 @@
     npmlog "^4.1.2"
     write-file-atomic "^2.3.0"
 
+"@mapbox/geojson-rewind@^0.5.0":
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/@mapbox/geojson-rewind/-/geojson-rewind-0.5.0.tgz#91f0ad56008c120caa19414b644d741249f4f560"
+  integrity sha512-73l/qJQgj/T/zO1JXVfuVvvKDgikD/7D/rHAD28S9BG1OTstgmftrmqfCx4U+zQAmtsB6HcDA3a7ymdnJZAQgg==
+  dependencies:
+    concat-stream "~2.0.0"
+    minimist "^1.2.5"
+
+"@mapbox/geojson-types@^1.0.2":
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/@mapbox/geojson-types/-/geojson-types-1.0.2.tgz#9aecf642cb00eab1080a57c4f949a65b4a5846d6"
+  integrity sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw==
+
+"@mapbox/jsonlint-lines-primitives@^2.0.2":
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz#ce56e539f83552b58d10d672ea4d6fc9adc7b234"
+  integrity sha1-zlblOfg1UrWNENZy6k1vya3HsjQ=
+
+"@mapbox/mapbox-gl-supported@^1.5.0":
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.5.0.tgz#f60b6a55a5d8e5ee908347d2ce4250b15103dc8e"
+  integrity sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg==
+
+"@mapbox/point-geometry@0.1.0", "@mapbox/point-geometry@^0.1.0", "@mapbox/point-geometry@~0.1.0":
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz#8a83f9335c7860effa2eeeca254332aa0aeed8f2"
+  integrity sha1-ioP5M1x4YO/6Lu7KJUMyqgru2PI=
+
+"@mapbox/tiny-sdf@^1.1.1":
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/@mapbox/tiny-sdf/-/tiny-sdf-1.1.1.tgz#16a20c470741bfe9191deb336f46e194da4a91ff"
+  integrity sha512-Ihn1nZcGIswJ5XGbgFAvVumOgWpvIjBX9jiRlIl46uQG9vJOF51ViBYHF95rEZupuyQbEmhLaDPLQlU7fUTsBg==
+
+"@mapbox/unitbezier@^0.0.0":
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz#15651bd553a67b8581fb398810c98ad86a34524e"
+  integrity sha1-FWUb1VOme4WB+zmIEMmK2Go0Uk4=
+
+"@mapbox/vector-tile@^1.3.1":
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz#d3a74c90402d06e89ec66de49ec817ff53409666"
+  integrity sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==
+  dependencies:
+    "@mapbox/point-geometry" "~0.1.0"
+
+"@mapbox/whoots-js@^3.1.0":
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz#497c67a1cef50d1a2459ba60f315e448d2ad87fe"
+  integrity sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==
+
 "@material-ui/core@4.9.0":
   version "4.9.0"
   resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.9.0.tgz#96ca3281ee06216d44fd4d0e306dbe0429eb2ebe"
@@ -1565,6 +1615,11 @@
     "@types/fbemitter" "*"
     "@types/react" "*"
 
+"@types/geojson@*":
+  version "7946.0.7"
+  resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad"
+  integrity sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==
+
 "@types/highlight.js@9.12.3":
   version "9.12.3"
   resolved "https://registry.yarnpkg.com/@types/highlight.js/-/highlight.js-9.12.3.tgz#b672cfaac25cbbc634a0fd92c515f66faa18dbca"
@@ -1592,6 +1647,13 @@
   dependencies:
     "@types/node" "*"
 
+"@types/mapbox-gl@^1.10.2":
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/@types/mapbox-gl/-/mapbox-gl-1.11.0.tgz#409d07bc6c85e3f14ba754b9e34c0e74809dabfc"
+  integrity sha512-Ni4i20zL+8Ynolk59qOILSfjGPxZ8kwNvmTd0fTXQVPbrNGbFXsNb2kTayi6yQiTV12y26l0dqjtH9n6QiT95Q==
+  dependencies:
+    "@types/geojson" "*"
+
 "@types/marked@0.6.0":
   version "0.6.0"
   resolved "https://registry.yarnpkg.com/@types/marked/-/marked-0.6.0.tgz#e4ac316144a84afda5c2474488d7b9fef3ab9995"
@@ -3222,7 +3284,7 @@
     readable-stream "^2.2.2"
     typedarray "^0.0.6"
 
-concat-stream@^2.0.0:
+concat-stream@^2.0.0, concat-stream@~2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1"
   integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==
@@ -3555,6 +3617,11 @@
   resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
   integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
 
+csscolorparser@~1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/csscolorparser/-/csscolorparser-1.0.3.tgz#b34f391eea4da8f3e98231e2ccd8df9c041f171b"
+  integrity sha1-s085HupNqPPpgjHizNjfnAQfFxs=
+
 cssesc@^0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
@@ -3997,6 +4064,11 @@
     readable-stream "^2.0.0"
     stream-shift "^1.0.0"
 
+earcut@^2.2.2:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/earcut/-/earcut-2.2.2.tgz#41b0bc35f63e0fe80da7cddff28511e7e2e80d11"
+  integrity sha512-eZoZPPJcUHnfRZ0PjLvx2qBordSiO8ofC3vt+qACLM95u+4DovnbYNpQtJh0DNsWj8RnxrQytD4WA8gj5cRIaQ==
+
 ecc-jsbn@~0.1.1:
   version "0.1.2"
   resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
@@ -4107,6 +4179,23 @@
   dependencies:
     is-arrayish "^0.2.1"
 
+es-abstract@^1.17.0-next.1, es-abstract@^1.17.5:
+  version "1.17.6"
+  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a"
+  integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==
+  dependencies:
+    es-to-primitive "^1.2.1"
+    function-bind "^1.1.1"
+    has "^1.0.3"
+    has-symbols "^1.0.1"
+    is-callable "^1.2.0"
+    is-regex "^1.1.0"
+    object-inspect "^1.7.0"
+    object-keys "^1.1.1"
+    object.assign "^4.1.0"
+    string.prototype.trimend "^1.0.1"
+    string.prototype.trimstart "^1.0.1"
+
 es-abstract@^1.5.1:
   version "1.16.0"
   resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.0.tgz#d3a26dc9c3283ac9750dca569586e976d9dcc06d"
@@ -4123,7 +4212,7 @@
     string.prototype.trimleft "^2.1.0"
     string.prototype.trimright "^2.1.0"
 
-es-to-primitive@^1.2.0:
+es-to-primitive@^1.2.0, es-to-primitive@^1.2.1:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
   integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
@@ -4772,6 +4861,11 @@
   resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537"
   integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==
 
+geojson-vt@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/geojson-vt/-/geojson-vt-3.2.1.tgz#f8adb614d2c1d3f6ee7c4265cad4bbf3ad60c8b7"
+  integrity sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==
+
 get-caller-file@^1.0.1:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
@@ -4881,6 +4975,11 @@
   resolved "https://registry.yarnpkg.com/github-markdown-css/-/github-markdown-css-2.10.0.tgz#0612fed22816b33b282f37ef8def7a4ecabfe993"
   integrity sha512-RX5VUC54uX6Lvrm226M9kMzsNeOa81MnKyxb3J0G5KLjyoOySOZgwyKFkUpv6iUhooiUZdogk+OTwQPJ4WttYg==
 
+gl-matrix@^3.2.1:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/gl-matrix/-/gl-matrix-3.3.0.tgz#232eef60b1c8b30a28cbbe75b2caf6c48fd6358b"
+  integrity sha512-COb7LDz+SXaHtl/h4LeaFcNdJdAQSDeVqjiIihSXNrkWObZLhDI4hIkZC11Aeqp7bcE72clzB0BnDXr2SmslRA==
+
 glob-base@^0.3.0:
   version "0.3.0"
   resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
@@ -5016,6 +5115,11 @@
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
   integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
 
+grid-index@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/grid-index/-/grid-index-1.1.0.tgz#97f8221edec1026c8377b86446a7c71e79522ea7"
+  integrity sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==
+
 growly@^1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
@@ -5097,6 +5201,11 @@
   resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
   integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
 
+has-symbols@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
+  integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
+
 has-unicode@^2.0.0, has-unicode@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
@@ -5439,7 +5548,7 @@
   dependencies:
     postcss "^6.0.1"
 
-ieee754@^1.1.4:
+ieee754@^1.1.12, ieee754@^1.1.4:
   version "1.1.13"
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
   integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
@@ -5693,6 +5802,11 @@
   resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
   integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==
 
+is-callable@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
+  integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==
+
 is-ci@^1.0.10:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
@@ -5905,6 +6019,13 @@
   dependencies:
     has "^1.0.1"
 
+is-regex@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff"
+  integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==
+  dependencies:
+    has-symbols "^1.0.1"
+
 is-ssh@^1.3.0:
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.3.1.tgz#f349a8cadd24e65298037a522cf7520f2e81a0f3"
@@ -6632,6 +6753,11 @@
     jwa "^1.4.1"
     safe-buffer "^5.0.1"
 
+kdbush@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/kdbush/-/kdbush-3.0.0.tgz#f8484794d47004cc2d85ed3a79353dbe0abc2bf0"
+  integrity sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==
+
 killable@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
@@ -7114,6 +7240,35 @@
   dependencies:
     object-visit "^1.0.0"
 
+mapbox-gl@^1.11.0:
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/mapbox-gl/-/mapbox-gl-1.11.0.tgz#7056d7cc1693e157eb5c2beb1476d620670d65e9"
+  integrity sha512-opIQf3C5RoKU5r9bHttTMhGAPcJet1/Cj2mdP7Ma2ylrAHjNPRc1i7KPyq8wjEZdJBMhd5qkIDlzUPM0TSncCQ==
+  dependencies:
+    "@mapbox/geojson-rewind" "^0.5.0"
+    "@mapbox/geojson-types" "^1.0.2"
+    "@mapbox/jsonlint-lines-primitives" "^2.0.2"
+    "@mapbox/mapbox-gl-supported" "^1.5.0"
+    "@mapbox/point-geometry" "^0.1.0"
+    "@mapbox/tiny-sdf" "^1.1.1"
+    "@mapbox/unitbezier" "^0.0.0"
+    "@mapbox/vector-tile" "^1.3.1"
+    "@mapbox/whoots-js" "^3.1.0"
+    csscolorparser "~1.0.3"
+    earcut "^2.2.2"
+    geojson-vt "^3.2.1"
+    gl-matrix "^3.2.1"
+    grid-index "^1.1.0"
+    minimist "^1.2.5"
+    murmurhash-js "^1.0.0"
+    pbf "^3.2.1"
+    potpack "^1.0.1"
+    quickselect "^2.0.0"
+    rw "^1.3.3"
+    supercluster "^7.1.0"
+    tinyqueue "^2.0.3"
+    vt-pbf "^3.1.1"
+
 marked@0.6.0:
   version "0.6.0"
   resolved "https://registry.yarnpkg.com/marked/-/marked-0.6.0.tgz#a18d01cfdcf8d15c3c455b71c8329e5e0f01faa1"
@@ -7507,6 +7662,11 @@
     arrify "^1.0.0"
     minimatch "^3.0.0"
 
+murmurhash-js@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/murmurhash-js/-/murmurhash-js-1.0.0.tgz#b06278e21fc6c37fa5313732b0412bcb6ae15f51"
+  integrity sha1-sGJ44h/Gw3+lMTcysEEry2rhX1E=
+
 mute-stream@0.0.7:
   version "0.0.7"
   resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
@@ -7857,9 +8017,9 @@
     npm-package-arg "^6.1.0"
 
 npm-registry-fetch@^4.0.0:
-  version "4.0.5"
-  resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-4.0.5.tgz#cb87cf7f25bfb048d6c3ee19d115bebf93ea5bfa"
-  integrity sha512-yQ0/U4fYpCCqmueB2g8sc+89ckQ3eXpmU4+Yi2j5o/r0WkKvE2+Y0tK3DEILAtn2UaQTkjTHxIXe2/CSdit+/Q==
+  version "4.0.7"
+  resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-4.0.7.tgz#57951bf6541e0246b34c9f9a38ab73607c9449d7"
+  integrity sha512-cny9v0+Mq6Tjz+e0erFAB+RYJ/AVGzkjnISiobqP8OWj9c9FLoZZu8/SPSKJWE17F1tk4018wfjV+ZbIbqC7fQ==
   dependencies:
     JSONStream "^1.3.4"
     bluebird "^3.5.1"
@@ -7937,6 +8097,11 @@
   resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67"
   integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==
 
+object-inspect@^1.7.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"
+  integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==
+
 object-is@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6"
@@ -7987,6 +8152,16 @@
   dependencies:
     isobject "^3.0.1"
 
+object.values@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e"
+  integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0-next.1"
+    function-bind "^1.1.1"
+    has "^1.0.3"
+
 obuf@^1.0.0, obuf@^1.1.2:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
@@ -8427,6 +8602,14 @@
   dependencies:
     pify "^3.0.0"
 
+pbf@^3.0.5, pbf@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/pbf/-/pbf-3.2.1.tgz#b4c1b9e72af966cd82c6531691115cc0409ffe2a"
+  integrity sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==
+  dependencies:
+    ieee754 "^1.1.12"
+    resolve-protobuf-schema "^2.1.0"
+
 pbkdf2@^3.0.3:
   version "3.0.17"
   resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6"
@@ -8580,6 +8763,11 @@
     source-map "^0.6.1"
     supports-color "^6.1.0"
 
+potpack@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.1.tgz#d1b1afd89e4c8f7762865ec30bd112ab767e2ebf"
+  integrity sha512-15vItUAbViaYrmaB/Pbw7z6qX2xENbFSTA7Ii4tgbPtasxm5v6ryKhKtL91tpWovDJzTiZqdwzhcFBCwiMVdVw==
+
 prelude-ls@~1.1.2:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@@ -8670,6 +8858,11 @@
   resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
   integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=
 
+protocol-buffers-schema@^3.3.1:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.4.0.tgz#2f0ea31ca96627d680bf2fefae7ebfa2b6453eae"
+  integrity sha512-G/2kcamPF2S49W5yaMGdIpkG6+5wZF0fzBteLKgEHjbNzqjZQ85aAs1iJGto31EJaSTkNvHs5IXuHSaTLWBAiA==
+
 protocols@^1.1.0, protocols@^1.4.0:
   version "1.4.7"
   resolved "https://registry.yarnpkg.com/protocols/-/protocols-1.4.7.tgz#95f788a4f0e979b291ffefcf5636ad113d037d32"
@@ -8802,6 +8995,11 @@
   resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
   integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
 
+quickselect@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018"
+  integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==
+
 randomatic@^3.0.0:
   version "3.1.1"
   resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed"
@@ -9361,6 +9559,13 @@
   resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd"
   integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==
 
+resolve-protobuf-schema@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz#9ca9a9e69cf192bbdaf1006ec1973948aa4a3758"
+  integrity sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==
+  dependencies:
+    protocol-buffers-schema "^3.3.1"
+
 resolve-url@^0.2.1:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
@@ -9435,6 +9640,11 @@
   dependencies:
     aproba "^1.1.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=
+
 rxjs@^6.4.0:
   version "6.5.5"
   resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.5.tgz#c5c884e3094c8cfee31bf27eb87e54ccfc87f9ec"
@@ -10030,6 +10240,14 @@
     is-fullwidth-code-point "^2.0.0"
     strip-ansi "^4.0.0"
 
+string.prototype.trimend@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
+  integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.5"
+
 string.prototype.trimleft@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634"
@@ -10046,6 +10264,14 @@
     define-properties "^1.1.3"
     function-bind "^1.1.1"
 
+string.prototype.trimstart@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
+  integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.5"
+
 string_decoder@^1.0.0, string_decoder@^1.1.1:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
@@ -10139,6 +10365,13 @@
     loader-utils "^1.1.0"
     schema-utils "^0.4.5"
 
+supercluster@^7.1.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/supercluster/-/supercluster-7.1.0.tgz#f0a457426ec0ab95d69c5f03b51e049774b94479"
+  integrity sha512-LDasImUAFMhTqhK+cUXfy9C2KTUqJ3gucLjmNLNFmKWOnDUBxLFLH9oKuXOTCLveecmxh8fbk8kgh6Q0gsfe2w==
+  dependencies:
+    kdbush "^3.0.0"
+
 supports-color@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
@@ -10324,6 +10557,11 @@
   resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
   integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
 
+tinyqueue@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-2.0.3.tgz#64d8492ebf39e7801d7bd34062e29b45b2035f08"
+  integrity sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==
+
 tmp@^0.0.33:
   version "0.0.33"
   resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@@ -10924,6 +11162,15 @@
   resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
   integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
 
+vt-pbf@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/vt-pbf/-/vt-pbf-3.1.1.tgz#b0f627e39a10ce91d943b898ed2363d21899fb82"
+  integrity sha512-pHjWdrIoxurpmTcbfBWXaPwSmtPAHS105253P1qyEfSTV2HJddqjM+kIHquaT/L6lVJIk9ltTGc0IxR/G47hYA==
+  dependencies:
+    "@mapbox/point-geometry" "0.1.0"
+    "@mapbox/vector-tile" "^1.3.1"
+    pbf "^3.0.5"
+
 w3c-hr-time@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045"