Compare commits

...

75 Commits

Author SHA1 Message Date
25ec6b6943 Cleanup maelstrom2-core
- Remove copied maelstrom-adapters plugin directory and refs
2019-08-12 16:12:41 -07:00
b628814f78 Remove copied maelstrom-adapters directory 2019-08-12 16:03:21 -07:00
a15ad6fc4c Maelstrom 2
- Updated composition export backup JSON file;
- Added MaelstromDictionary.js for backup;
2019-08-09 19:22:38 -07:00
767aa78b06 Maelstrom 2
- Added composition export backup JSON file to repo;
2019-08-09 16:45:42 -07:00
43b7efa775 Maelstrom 2 updated to latest TCR
- Merge, resolve conflicts;
- Added plugin installation in index.html for Gauge and Bignumbers;
- Fixed frame styling issues in theme-maelstrom.scss;
2019-08-09 16:44:22 -07:00
ac18548b42 Merge branch 'maelstrom2-core' of https://github.com/nasa/openmct into maelstrom2-core 2019-08-09 15:51:50 -07:00
ed3c226909 Maelstrom 2
- Add adapters
2019-08-09 15:49:57 -07:00
261e8e8759 Maelstrom 2 WIP
- Fixed layout tweaks for RPY plot;
- Added pulse to passenger notice in nominal mode;
2019-05-20 20:50:13 -07:00
cb6a8629d3 Maelstrom 2 WIP
- Tweaks;
- Styling for plot element in Attitude component;
2019-05-15 22:13:25 -07:00
9eead672d8 Maelstrom 2 WIP
- Added Bg Widget styling;
- Added pulse-fast class;
2019-05-04 01:20:32 -07:00
5da6b2c969 Maelstrom 2 WIP
- Major style refinements and additions;
- Added next-los to Dictionary;
2019-05-03 19:18:45 -07:00
4780cde3b5 Merge branch 'topic-core-refactor' into maelstrom2-core 2019-05-03 15:39:59 -07:00
1960215fc1 Maelstrom 2 WIP
- Styling for "EVRs" LAD wtable in Sys Ovw;
2019-04-28 22:42:33 -07:00
d06e3e12fc Merge latest TCR; add EVRs 1-5 to Maelstrom Dictionary 2019-04-28 22:41:21 -07:00
365998ad4f Maelstrom 2 core WIP
- Install maelstrom-adapters;
2019-04-28 14:57:40 -07:00
15cfa79106 Maelstrom 2 styling WIP
- Ring widgets styling;
- Minor admin;
2019-04-26 18:42:06 -07:00
6857e15a83 Radial Gauge
- Dial now doesn't break if current value if greater than high limit;
2019-04-26 18:41:14 -07:00
f1294f3e73 Maelstrom 2 WIP
- Event Time Str element styling;
2019-04-21 23:22:44 -07:00
d4a1f6eb35 Maelstrom 2 WIP
- Boost Phase component styles;
2019-04-19 16:11:45 -07:00
4c7fb0d3eb Maelstrom 2 WIP
- Much better pulse mixin;
- pulse-* styles defined;
- Layout, Time Conductor refinements;
2019-04-19 01:15:18 -07:00
b9017329cd Maelstrom2 WIP
- Hide s-selected border in browse mode;
- Refined timer styles;
2019-04-18 00:47:25 -07:00
b08834a53b Important enhancements to Gauge:
- Number of decimals and whether Min and Max values should be displayed
are now configurable properties;
2019-04-18 00:46:21 -07:00
eb7330522e Maelstrom2
- Timer styling
2019-04-17 01:16:22 -07:00
0c1cdf1d8e Merge branch 'misc-fixes-2' into maelstrom2-core 2019-04-17 00:21:21 -07:00
8dedf52910 Maelstrom2
- colors, styling WIP
- New _movie overrides scss file;
2019-04-17 00:15:39 -07:00
0420eac159 Cherry pick: Misc Fixes 2
- Better approach to title in layout frames;
- Removed unneeded !important attribs;
2019-04-16 23:33:47 -07:00
715e3419a0 Maelstrom2 styling
- Body font size enlarged;
- Alignment in __header__name fixed;
2019-04-16 22:21:17 -07:00
e6ab3ccf85 Misc Fixes 2
- Restore erroneous delete;
2019-04-16 22:03:56 -07:00
edf748d4a1 Misc Fixes 2
- Fix alignment issue in c-so-view__headers;
2019-04-16 22:01:36 -07:00
84ba444eb5 Merge latest TCR, resolve minor conflicts 2019-04-16 21:32:45 -07:00
6d9f3f1e3e Cherry pick merge from misc-ui-7 0908b43 2019-04-04 00:44:08 -07:00
ae32b902a7 Significant progress on Maelstrom 2 base styling
- New theme file;
- Mods to theme constants;
2019-04-04 00:25:41 -07:00
660bf805d0 Fix merge booboo in plugins.js 2019-04-02 22:54:24 -07:00
2f58ea9c1f Merge latest TCR, resolve minor conflicts 2019-04-02 22:36:35 -07:00
ba09a17b29 Get bignumbers object wired up
- Added subscription methods from gauge (thanks Deep!);
- JS now splits number into decimal and integer;
- Mod to integer SVG display to use lengthAdjust=spacingAndGlyphs;
2019-02-02 19:20:04 -08:00
5063fa1fb1 Set gauge initial value to 0 2019-02-02 19:17:54 -08:00
543b4dab4c Allow bignumbers object type to be editable. 2019-02-02 17:20:15 -08:00
ef310a8777 make gauge view editable 2019-02-02 17:11:02 -08:00
7d07a9e21f Delete out-of-date constants scss file 2019-02-02 16:42:54 -08:00
ada18faa98 Merge in latest TCR, fix conflicts 2019-02-02 16:39:45 -08:00
95d40aaeed add telemetry support with updating values 2018-11-27 16:12:55 -08:00
b59f5c70dc Rename Bigalpha to Bignumbers
- Tweak layout as well;
2018-11-22 20:32:38 -08:00
94e7351e22 Various
- Fixed config properties;
- Added method to zero pad values;
2018-11-22 16:32:16 -08:00
50ee7353b1 Back to original hero font; better char spacing
- Layout and char spacing tweaks;
- TODOs: change properties;
2018-11-21 23:50:00 -08:00
df524c4f48 Layout finessing for new hero font WIP
- Added Share Tech Mono font, change to use;
- Layout tweaks;
2018-11-21 15:10:46 -08:00
aa59692585 Element layout WIP 2018-11-20 23:16:18 -08:00
0bf82956ab Add new bigAlpha component 2018-11-20 22:15:47 -08:00
f102158ba0 add form with min, max, limit values when creating gauge 2018-11-12 09:41:12 -08:00
9a51bb71b9 Suppress background of frames in Layout 2018-11-10 23:54:25 -08:00
12b9aa75a3 Added object name as title of frame in LayoutItem 2018-11-10 23:50:16 -08:00
5bedfc2efd Merged in fixed baseline in symbols font from TCR 2018-11-10 22:42:58 -08:00
212d7c3eae Merge branch 'gauges' into maelstrom2-core 2018-11-10 22:35:45 -08:00
d7a3510f34 Fixed code issues in gaugeRadial 2018-11-10 22:35:19 -08:00
9cc44dcc4e Color tweaks, View Controls color refined 2018-11-10 00:16:02 -08:00
f42a5e19f0 Fixed symbols-font baselines; theme parity
- open-mct-symbols font baseline set to 0, better alignment;
- espresso and snow themes now aligned to approach in maelstrom2;
2018-11-09 22:42:25 -08:00
102cfc33c4 Merge latest TCR, resolve conflicts
- Mostly TCR wins, check for issues...
2018-11-09 22:11:24 -08:00
957c7102fe Merge latest TCR, resolve conflicts
- Mostly TCR wins, check for issues...
2018-11-09 22:06:20 -08:00
0519824109 Added todo 2018-11-08 00:07:10 -08:00
4380f88a08 Apply hero font to gauge
- Placing, sizing;
2018-11-08 00:05:28 -08:00
20d5db6e44 Change default Fixed Layout grid sizing 2018-11-07 23:58:59 -08:00
5978b8e19d Added new theme stylesheet
- Loads thematic fonts;
- Font mixins;
- Override styling for c-frame;
2018-11-07 23:58:26 -08:00
a0b71f92b8 Merge branch 'gauges' into maelstrom2-core 2018-11-07 22:38:27 -08:00
7c3f7ff384 Added description 2018-11-07 22:38:05 -08:00
6f2a567299 Merge in latest topic-core-refactor 2018-11-07 22:34:04 -08:00
746badd065 Merge in gauges branch 2018-11-07 22:30:58 -08:00
7d99877eb9 Fixed dial value SVG path to avoid visual overflow at 90 deg 2018-11-06 23:52:40 -08:00
3eac91a6d9 Added gauge icon 2018-11-06 23:31:02 -08:00
4d426580ae Gauge now a plugin 2018-11-06 22:48:24 -08:00
9270f02ca4 Merge branch 'topic-core-refactor' into gauges 2018-11-06 22:11:03 -08:00
815b1449f4 Merge branch 'topic-core-refactor' into gauges 2018-11-05 19:53:48 -08:00
0874ada4d2 Maths fixed!
TODO: clipping path shows a little sliver of dial at 90%;
2018-10-31 01:20:32 -07:00
03812437d3 Current value and ranges now SVG text
- Scales properly;
- Math enhancements;
- TODO: fix math when negative numbers involved;
2018-10-31 00:15:15 -07:00
2b8272cf05 Adding dynamic SVG text 2018-10-30 09:54:00 -07:00
71a2f27e0c Refined art, WIP 2018-10-26 09:39:47 -07:00
5460ca2009 Initial markup, CSS and code for radial gauge
- WIP!
2018-10-25 10:21:57 -07:00
18 changed files with 1643 additions and 16 deletions

View File

@ -0,0 +1,487 @@
export default {
'telemetry': {
type: 'folder',
name: 'Maelstrom Telemetry',
type: 'folder',
location: 'ROOT',
composition: [
{
namespace: 'maelstrom',
key: 'velocity'
},{
namespace: 'maelstrom',
key: 'acceleration-ms-2'
},{
namespace: 'maelstrom',
key: 'acceleration-g'
},{
namespace: 'maelstrom',
key: 'distance'
},{
namespace: 'maelstrom',
key: 'distance-m'
},{
namespace: 'maelstrom',
key: 'roll'
},{
namespace: 'maelstrom',
key: 'pitch'
},{
namespace: 'maelstrom',
key: 'yaw'
},{
namespace: 'maelstrom',
key: 'event-index'
},{
namespace: 'maelstrom',
key: 'event-time-str'
},{
namespace: 'maelstrom',
key: 'ring'
},{
namespace: 'maelstrom',
key: 'next-los'
},{
namespace: 'maelstrom',
key: 'evr-1'
},{
namespace: 'maelstrom',
key: 'evr-2'
},{
namespace: 'maelstrom',
key: 'evr-3'
},{
namespace: 'maelstrom',
key: 'evr-4'
},{
namespace: 'maelstrom',
key: 'evr-5'
}
]
},
'velocity': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Velocity',
telemetry: {
values: [{
"key": "value",
"name": "Velocity",
"units": "ms",
"format": "float",
"source": "velocity",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'acceleration-ms-2': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Acceleration (ms^-2)',
telemetry: {
values: [{
"key": "value",
"name": "Acceleration",
"units": "ms^-2",
"format": "float",
"source": "acceleration-ms-2",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'acceleration-g': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Acceleration (G)',
telemetry: {
values: [{
"key": "value",
"name": "Acceleration",
"units": "ms^-2",
"format": "float",
"source": "acceleration-g",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'distance': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Distance (km)',
telemetry: {
values: [{
"key": "value",
"name": "Distance",
"units": "km",
"format": "float",
"source": "distance-km",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'distance-m': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Distance (m)',
telemetry: {
values: [{
"key": "value",
"name": "Distance Meters",
"units": "m",
"format": "float",
"source": "distance-m",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'roll': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Roll',
telemetry: {
values: [{
"key": "value",
"name": "Roll",
"units": "degrees",
"format": "float",
"source": "roll",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'pitch': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Pitch',
telemetry: {
values: [{
"key": "value",
"name": "Pitch",
"units": "degrees",
"format": "float",
"source": "pitch",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'yaw': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Yaw',
telemetry: {
values: [{
"key": "value",
"name": "Yaw",
"units": "degrees",
"format": "float",
"source": "yaw",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'event-index': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Event Index',
telemetry: {
values: [{
"key": "value",
"name": "Event Index",
"units": "i",
"format": "float",
"source": "event-index",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'event-time-str': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Event Time Str',
telemetry: {
values: [{
"key": "value",
"name": "Event Time Str",
"units": "",
"format": "string",
"source": "event-time-str",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'ring': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Ring',
telemetry: {
values: [{
"key": "value",
"name": "Ring",
"units": "",
"format": "int",
"source": "ring",
"hints": {
"range": 24
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'next-los': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'Next LOS',
telemetry: {
values: [{
"key": "value",
"name": "Next LOS",
"units": "",
"format": "string",
"source": "next-los",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'evr-1': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'EVR 1',
telemetry: {
values: [{
"key": "value",
"name": "EVR-1",
"units": "",
"format": "string",
"source": "evr-1",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'evr-2': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'EVR 2',
telemetry: {
values: [{
"key": "value",
"name": "EVR-2",
"units": "",
"format": "string",
"source": "evr-2",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'evr-3': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'EVR 3',
telemetry: {
values: [{
"key": "value",
"name": "EVR-3",
"units": "",
"format": "string",
"source": "evr-3",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'evr-4': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'EVR 4',
telemetry: {
values: [{
"key": "value",
"name": "EVR-4",
"units": "",
"format": "string",
"source": "evr-4",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
},
'evr-5': {
type: 'maelstrom-telemetry',
location: 'maelstrom:telemetry',
name: 'EVR 5',
telemetry: {
values: [{
"key": "value",
"name": "EVR-5",
"units": "",
"format": "string",
"source": "evr-5",
"hints": {
"range": 1
}
}, {
"key": "utc",
"source": "event_time",
"name": "Time",
"format": "utc-diy",
"hints": {
"domain": 1
}
}
]}
}
}

File diff suppressed because one or more lines are too long

View File

@ -45,6 +45,8 @@
].forEach(
openmct.legacyRegistry.enable.bind(openmct.legacyRegistry)
);
openmct.install(openmct.plugins.Bignumbers());
openmct.install(openmct.plugins.Gauge());
openmct.install(openmct.plugins.MyItems());
openmct.install(openmct.plugins.LocalStorage());
openmct.install(openmct.plugins.Generator());

View File

@ -5,7 +5,7 @@
*
* Open MCT is 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
* You may obtain a copy of the License atw
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software

View File

@ -0,0 +1,71 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is 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.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
'./components/bignumbers.vue',
'vue'
], function (
BignumbersComponent,
Vue
) {
function Bignumbers(openmct) {
return {
key: 'bignumbers',
name: 'Bignumbers',
cssClass: 'icon-telemetry',
canView: function (domainObject) {
return domainObject.type === 'bignumbers';
},
canEdit: function (domainObject) {
return domainObject.type === 'bignumbers';
},
view: function (domainObject) {
let component;
return {
show: function (element) {
component = new Vue({
components: {
BignumbersComponent: BignumbersComponent.default
},
provide: {
openmct,
domainObject,
composition: openmct.composition.get(domainObject)
},
el: element,
template: '<bignumbers-component></bignumbers-component>'
});
},
destroy: function (element) {
component.$destroy();
component = undefined;
}
};
},
priority: function () {
return 1;
}
};
}
return Bignumbers;
});

View File

@ -0,0 +1,131 @@
<template>
<div class="c-bignumbers">
<svg class="c-bignumbers__int" viewBox="0 0 52 32">
<text textLength=100% lengthAdjust=spacingAndGlyphs x="0" y="32">{{ this.curValInt }}</text>
</svg>
<svg class="c-bignumbers__dec" viewBox="0 0 40 20">
<text textLength=100% lengthAdjust=spacing x="0" y="20">.{{ this.curValDec }}</text>
</svg>
<svg class="c-bignumbers__units" viewBox="0 0 45 11">
<text textLength=100% lengthAdjust=spacingAndGlyphs x="0" y="11">{{ this.units }}</text>
</svg>
</div>
</template>
<style lang="scss">
@import "~styles/sass-base";
.c-bignumbers {
$w1: 53%;
@include abs();
bottom: auto;
padding-bottom: 33%;
&__int,
&__dec,
&__units {
position: absolute;
fill: #fff;
}
&__int,
&__dec {
font-family: $heroFont;
}
&__int {
font-size: 51px;
opacity: 0.8;
width: $w1;
}
&__dec {
left: $w1;
font-size: 32px;
opacity: 0.4;
width: 100% - $w1;
}
&__units {
font-size: 9px;
font-family: $headerFont;
left: $w1;
bottom: 0;
opacity: 0.2;
width: 99% - $w1; // Font has different char spacing, so use reduced width
}
}
</style>
<script>
export default {
name: "bignumbers",
inject: ['openmct', 'domainObject', 'composition'],
data: function () {
let config = this.domainObject.configuration,
units = config.units;
console.log(config);
return {
curValInt: 0,
curValDec: 0,
units: units
}
},
methods: {
getInt: function(val, digits) {
// Extract integer portion of val and zero-pad it if its length < digits
return this.zeroPad(Math.floor(val), digits);
},
getDec: function(val, digits) {
// Extract decimal portion of val to the specified number of digits
return Number.parseFloat(val).toFixed(digits).split('.')[1];
},
zeroPad: function(val, length) {
// Zero pads an integer and returns it as a string
let s = Math.abs(val).toString();
if (s.length < length) {
for (let i = 0; i <= (length - s.length); i++) {
s = '0' + s;
}
}
if (val < 0) {
s = '-' + s;
}
return s;
},
updateValue(datum) {
let cv = this.formats[this.valueKey].format(datum);
this.curValInt = this.getInt(cv, 3);
this.curValDec = this.getDec(cv, 3);
},
subscribe(domainObject) {
this.metadata = this.openmct.telemetry.getMetadata(domainObject);
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
this.valueKey = this
.metadata
.valuesForHints(['range'])[0].key;
this.unsubscribe = this.openmct
.telemetry
.subscribe(domainObject, this.updateValue.bind(this), {});
this.openmct
.telemetry
.request(domainObject, {strategy: 'latest'})
.then((values) => values.forEach(this.updateValue));
}
},
computed: {
},
mounted() {
this.composition.on('add', this.subscribe);
this.composition.load();
},
destroyed() {
this.composition.off('add', this.subscribe);
this.unsubscribe();
}
}
</script>

View File

@ -0,0 +1,58 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is 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.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
'./bignumbers'
], function (
Bignumbers
) {
return function plugin() {
return function install(openmct) {
openmct.objectViews.addProvider(new Bignumbers(openmct));
openmct.types.addType('bignumbers', {
name: "Big Numbers",
creatable: true,
description: "Display the value of a telemetry element with units in a stylized numeric view.",
cssClass: 'icon-telemetry',
initialize(domainObject) {
domainObject.composition = [];
domainObject.configuration = {
units: ''
};
},
form: [
{
name: "Units",
control: "textfield",
cssClass: "",
key: "units",
property: [
"configuration",
"units"
]
}
]
});
};
};
});

View File

@ -0,0 +1,202 @@
<template>
<div class="c-gauge">
<div class="c-gauge__wrapper">
<svg class="c-gauge__range" viewBox="0 0 512 512">
<text class="c-gauge__curval" transform="translate(256 310)" text-anchor="middle">{{ this.curVal }}</text>
<text font-size="35" transform="translate(105 455) rotate(-45)"
v-if="displayMinMax">{{ this.rangeLow }}</text>
<text font-size="35" transform="translate(407 455) rotate(45)" text-anchor="end"
v-if="displayMinMax">{{ this.rangeHigh }}</text>
</svg>
<div class="c-dial">
<svg class="c-dial__bg" viewBox="0 0 512 512">
<g>
<path d="M256,0C114.6,0,0,114.6,0,256S114.6,512,256,512,512,397.4,512,256,397.4,0,256,0Zm0,412A156,156,0,1,1,412,256,155.9,155.9,0,0,1,256,412Z"/>
</g>
</svg>
<svg class="c-dial__limit" viewBox="0 0 512 512"
v-if="degLimit < 270"
:class="{
'c-limit-clip--90': this.degLimit > 90,
'c-limit-clip--180': this.degLimit >= 180
}">
<path d="M100,256A156,156,0,1,1,366.3,366.3L437,437a255.2,255.2,0,0,0,75-181C512,114.6,397.4,0,256,0S0,114.6,0,256A255.2,255.2,0,0,0,75,437l70.7-70.7A155.5,155.5,0,0,1,100,256Z"
:style="`transform: rotate(${this.degLimit}deg)`"/>
</svg>
<svg class="c-dial__value" viewBox="0 0 512 512"
v-if="this.degValue > 0"
:class="{
'c-dial-clip--90': this.degValue < 90,
'c-dial-clip--180': this.degValue >= 90 && this.degValue < 180
}">
<path d="M256,31A224.3,224.3,0,0,0,98.3,95.5l48.4,49.2a156,156,0,1,1-1,221.6L96.9,415.1A224.4,224.4,0,0,0,256,481c124.3,0,225-100.7,225-225S380.3,31,256,31Z"
:style="`transform: rotate(${this.degValue}deg)`"/>
</svg>
</div>
</div>
</div>
</template>
<style lang="scss">
@import "~styles/sass-base";
.c-gauge {
@include abs();
overflow: hidden;
&__wrapper {
position: absolute;
width: 100%;
padding-bottom: 100%;
overflow: hidden;
}
&__value {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
font-size: 3vw;
}
&__range {
$o: 21%;
position: absolute;
fill: rgba(#fff, 0.8);
}
&__curval {
font-family: $heroFont;
font-size: 170px;
}
}
.c-dial {
// Dial elements
@include abs();
clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 50%, 0 100%);
svg,
&__ticks,
&__bg,
&__limit,
&__value {
@include abs();
}
svg {
path {
transform-origin: center;
}
}
&__limit {
&.c-limit-clip--90 {
clip-path: polygon(0 0, 100% 0, 100% 100%);
}
&.c-limit-clip--180 {
clip-path: polygon(100% 0, 100% 100%, 0 100%);
}
path {
fill: rgba(orange, 0.4);
}
}
&__value {
&.c-dial-clip--90 {
clip-path: polygon(0 0, 50% 50%, 0 100%);
}
&.c-dial-clip--180 {
clip-path: polygon(0 0, 100% 0, 0 100%);
}
path {
fill: rgba(#fff, 0.8);
}
}
&__bg {
g {
fill: rgba(#fff, 0.1);
}
}
}
</style>
<script>
export default {
name: "gaugeRadial",
inject: ['openmct', 'domainObject', 'composition'],
data: function () {
let config = this.domainObject.configuration,
rangeLow = config.min,
rangeHigh = config.max,
displayMinMax = config.displayMinMax,
limit = config.limit,
decimals = config.decimals;
return {
rangeLow,
rangeHigh,
displayMinMax: displayMinMax.indexOf('Yes') !== -1,
limit1: limit,
decimals,
curVal: 0
}
},
methods: {
round: function(val, decimals) {
let precision = Math.pow(10, decimals);
return Math.round(val * precision)/precision;
},
valToPercent: function(vValue) {
// Don't let the current value exceed the high range, or the dial won't display right
if (vValue >= this.rangeHigh) { return 100; }
return ((vValue - this.rangeLow) / (this.rangeHigh - this.rangeLow)) * 100;
},
percentToDegrees: function(vPercent) {
return this.round((vPercent/100)*270, 2);
},
updateValue(datum) {
this.curVal = this.round(this.formats[this.valueKey].format(datum), this.decimals);
},
subscribe(domainObject) {
this.metadata = this.openmct.telemetry.getMetadata(domainObject);
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
this.valueKey = this
.metadata
.valuesForHints(['range'])[0].key;
this.unsubscribe = this.openmct
.telemetry
.subscribe(domainObject, this.updateValue.bind(this), {});
this.openmct
.telemetry
.request(domainObject, {strategy: 'latest'})
.then((values) => values.forEach(this.updateValue));
}
},
computed: {
degValue: function() {
return this.percentToDegrees(this.valToPercent(this.curVal));
},
degLimit: function() {
return this.percentToDegrees(this.valToPercent(this.limit1));
}
},
mounted() {
this.composition.on('add', this.subscribe);
this.composition.load();
},
destroyed() {
this.composition.off('add', this.subscribe);
this.unsubscribe();
}
}
</script>

View File

@ -0,0 +1,71 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is 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.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
'./components/gaugeRadial.vue',
'vue'
], function (
GaugeComponent,
Vue
) {
function Gauge(openmct) {
return {
key: 'gauge',
name: 'Gauge',
cssClass: 'icon-gauge',
canView: function (domainObject) {
return domainObject.type === 'gauge';
},
canEdit: function (domainObject) {
return domainObject.type === 'gauge';
},
view: function (domainObject) {
let component;
return {
show: function (element) {
component = new Vue({
components: {
GaugeComponent: GaugeComponent.default
},
provide: {
openmct,
domainObject,
composition: openmct.composition.get(domainObject)
},
el: element,
template: '<gauge-component></gauge-component>'
});
},
destroy: function (element) {
component.$destroy();
component = undefined;
}
};
},
priority: function () {
return 1;
}
};
}
return Gauge;
});

102
src/plugins/gauge/plugin.js Normal file
View File

@ -0,0 +1,102 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is 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.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
'./gauge'
], function (
Gauge
) {
return function plugin() {
return function install(openmct) {
openmct.objectViews.addProvider(new Gauge(openmct));
openmct.types.addType('gauge', {
name: "Gauge",
creatable: true,
description: "Graphically visualize a telemetry element's current value between a minimum and maximum.",
cssClass: 'icon-gauge',
initialize(domainObject) {
domainObject.composition = [];
domainObject.configuration = {
min: 0,
max: 100,
displayMinMax: 'Yes',
limit: 90,
decimals: 1
};
},
form: [
{
name: "Minimum Value",
control: "numberfield",
cssClass: "l-input-sm l-numeric",
key: "min",
property: [
"configuration",
"min"
]
},
{
name: "Maximum Value",
control: "numberfield",
cssClass: "l-input-sm l-numeric",
key: "max",
property: [
"configuration",
"max"
]
},
{
name: "Display Min/Max",
control: "textfield",
cssClass: "l-input-sm",
key: "displayMinMax",
property: [
"configuration",
"displayMinMax"
]
},
{
name: "Limit",
control: "numberfield",
cssClass: "l-input-sm l-numeric",
key: "min",
property: [
"configuration",
"limit"
]
},
{
name: "Decimals",
control: "numberfield",
cssClass: "l-input-sm l-numeric",
key: "decimals",
property: [
"configuration",
"decimals"
]
}
]
});
};
};
});

View File

@ -44,7 +44,9 @@ define([
'./filters/plugin',
'./objectMigration/plugin',
'./goToOriginalAction/plugin',
'./clearData/plugin'
'./clearData/plugin',
'./gauge/plugin',
'./bignumbers/plugin'
], function (
_,
UTCTimeSystem,
@ -69,7 +71,9 @@ define([
Filters,
ObjectMigration,
GoToOriginalAction,
ClearData
ClearData,
Gauge,
Bignumbers
) {
var bundleMap = {
LocalStorage: 'platform/persistence/local',
@ -101,7 +105,6 @@ define([
* to exclusively.
*/
plugins.AutoflowView = AutoflowPlugin;
plugins.Conductor = TimeConductorPlugin.default;
plugins.CouchDB = function (url) {
@ -169,6 +172,8 @@ define([
plugins.ObjectMigration = ObjectMigration.default;
plugins.GoToOriginalAction = GoToOriginalAction.default;
plugins.ClearData = ClearData;
plugins.Gauge = Gauge;
plugins.Bignumbers = Bignumbers;
return plugins;
});

View File

@ -36,9 +36,10 @@ $bodyFont: 'Chakra Petch', sans-serif;
@mixin headerFont($size: 1em) {
font-family: $headerFont;
font-size: $size * 0.8; // This font is comparatively large, so reduce it a bit
font-size: $size;
line-height: $size;
text-transform: uppercase;
word-spacing: 0.25em;
word-spacing: 0.4em;
}
@mixin bodyFont($size: 1em) {
@ -68,12 +69,15 @@ $shdwBtns: rgba(black, 0.2) 0 1px 2px;
$shdwBtnsOverlay: rgba(black, 0.5) 0 1px 5px;
// Base colors
$colorBodyBg: #393939;
$colorBodyBg: #000000;
$colorBodyFg: #ccc;
$colorBodyFgEm: #fff;
$colorGenBg: #222;
$colorHeadBg: #262626;
$colorHeadBg: transparent;
$colorHeadFg: $colorBodyFg;
$colorStatusBarBg: $colorHeadBg;
$colorStatusBarFg: rgba(white, 0.5);
$colorStatusBarFgHov: #aaa;
$colorKey: #0099cc;
$colorKeyFg: #fff;
$colorKeyHov: #26d8ff;
@ -185,7 +189,7 @@ $colorIconAliasForKeyFilter: #aaa;
$colorTabsHolderBg: rgba(black, 0.2);
// Buttons and Controls
$colorBtnBg: pullForward($colorBodyBg, 10%);
$colorBtnBg: pullForward($colorBodyBg, 30%);
$colorBtnBgHov: pullForward($colorBtnBg, 10%);
$colorBtnFg: pullForward($colorBodyFg, 10%);
$colorBtnReverseFg: pullForward($colorBtnFg, 10%);

View File

@ -42,6 +42,31 @@ $bodyFont: $heroFont;
font-size: $size;
}
// FONTS
@import url('https://fonts.googleapis.com/css?family=Chakra+Petch:400,600,700|Michroma|Teko:400,700');
$heroFont: "Helvetica Neue", Helvetica, Arial, sans-serif;
$headerFont: $heroFont;
$bodyFont: $heroFont;
@mixin heroFont($size: 1em) {
$mult: 1;
font-family: $heroFont;
font-size: $size * $mult;
}
@mixin headerFont($size: 1em) {
$mult: 1;
font-family: $headerFont;
font-size: $size * $mult;
}
@mixin bodyFont($size: 1em) {
$mult: 1;
font-family: $bodyFont;
font-size: $size * $mult;
}
// Functions
@function buttonBg($c: $colorBtnBg) {
@return $c;

View File

@ -50,14 +50,14 @@
}
/************************** EFFECTS */
@mixin pulse($animName: pulse, $dur: 500ms, $iteration: infinite, $opacity0: 0.5, $opacity100: 1) {
@keyframes pulse {
0% { opacity: $opacity0; }
100% { opacity: $opacity100; }
@mixin pulse($animName: 'pulse', $dur: 500ms, $iteration: infinite, $prop: opacity, $val0: 0, $val100: 1, $direction: alternate) {
@keyframes #{$animName} {
0% { #{$prop}: $val0; }
100% { #{$prop}: $val100; }
}
animation-name: $animName;
animation-duration: $dur;
animation-direction: alternate;
animation-direction: $direction;
animation-iteration-count: $iteration;
animation-timing-function: ease-in-out;
}

View File

@ -0,0 +1,447 @@
/**************************************************** CONSTANTS, MIXINS */
$bgKey: #222632;
$redKeyBg: #990000;
$redKeyBrdr: #ff0000;
$redKeyFg: rgba(white, 0.8);
$ylwKeyBg: #cc6b36;
$ylwKeyBrdr: #ffbf1a;
$ylwKeyFg: rgba(white, 0.8);
@mixin widgetOk() {
background-color: #bbb !important;
border-color: #fff !important;
color: #333 !important;
}
@mixin widgetRed() {
background-color: $redKeyBg !important;
border-color: $redKeyBrdr !important;
color: $redKeyFg !important;
}
@mixin widgetYellow() {
$c: $ylwKeyFg;
background-color: $ylwKeyBg !important;
border-color: $ylwKeyBrdr !important;
color: $ylwKeyFg !important;
}
/**************************************************** OVERRIDES */
body {
font-size: 1em;
}
.c-telemetry-view__value {
justify-content: center;
&[class*='is-limit'] {
background: transparent !important;
color: inherit !important;
&:before { display: none; }
}
}
/**************************************************** CONVENIENCE */
.u-inspectable[s-selected] {
border: none !important;
}
.c-table.c-telemetry-table {
font-size: 0.7em;
}
.widget-rule-content .t-rule-message-input {
width: 100%;
}
/**************************************************** TIME CONDUCTOR */
.c-conductor {
&__controls {
display: none !important;
}
&:hover {
.c-conductor__controls { display: flex !important; }
}
[class*='__label'] {
display: none;
}
&__end-fixed {
display: none;
}
&__end-delta {
&:after {
content: '';
display: block;
background: url('../ui/layout/assets/images/logo-app.svg') center no-repeat;
background-size: contain;
width: 100px;
height: 24px;
}
}
&-input {
input {
&.c-input--datetime,
&.c-input--hrs-min-sec {
color: $colorTime;
width: 200px;
}
&.c-input--hrs-min-sec {
width: 80px;
}
}
}
}
/**************************************************** MAIN LAYOUT */
.l-shell {
&:not(.is-editing) {
.l-shell__head,
.l-shell__main-view-browse-bar {
background: none !important;
height: $interiorMargin;
overflow: hidden;
padding: 0 !important;
position: absolute;
width: 30%;
z-index: 100;
* { opacity: 0; }
&:hover {
background: #666 !important;
height: auto;
overflow: visible;
padding: $interiorMargin !important;
* { opacity: 1; }
}
}
.l-shell__pane-main .l-pane__contents > * + * {
margin-top: 0;
}
.l-shell__main-container {
margin-top: 0 !important;
}
}
.l-shell__main-view-browse-bar {
top: -3px; right: 0;
}
&__main > .l-pane {
padding-left: $interiorMargin !important;
padding-right: $interiorMargin !important;
}
&__status { display: none !important; }
}
.l-pane {
&__contents {
overflow: visible !important;
}
&--collapsed {
$d: 5px;
flex-basis: $d !important;
min-width: $d !important;
min-height: $d !important;
.l-pane__label {
display: none !important;
}
.l-pane__collapse-button {
&:before { display: none !important; }
}
}
}
/**************************************************** STYLING BY TITLE */
*[title*='font-euro'] {
@include headerFont();
}
*[title*='key-widget'] {
font-size: 24px;
}
*[title*='alert-red'] {
.c-sw__icon {
color: red !important;
}
}
*[title*='alert-yellow'] {
.c-sw__icon {
color: $ylwKeyBg !important;
}
}
*[title*='widget-ok'] {
@include widgetOk();
}
*[title*='widget-yellow'] {
@include widgetYellow();
}
*[title*='widget-red'] {
@include widgetRed();
}
*[title*='pulse-slow'] {
@include pulse($animName: pulseSlow, $dur: 1000ms, $prop: filter, $val0: brightness(1.2), $val100: brightness(0.6), $direction: normal);
.c-sw__icon {
@include pulse($animName: pulseWarningIcon, $dur: 500ms, $prop: opacity, $val0: 0.1, $val100: 1, $direction: normal);
}
}
*[title*='pulse-fast'] {
@include pulse($animName: pulseSlow, $dur: 250ms, $prop: filter, $val0: brightness(1.5), $val100: brightness(0.9), $direction: normal);
}
*[title*='pulse-warning'] {
@include pulse($animName: pulseWarning, $dur: 1500ms, $prop: filter, $val0: brightness(1.2), $val100: brightness(0.7), $direction: normal);
}
*[title*='Bg Widget'] {
// Widgets that provide a flashing red bg for components
.c-summary-widget {
$b: 5px;
border: none !important;
border-radius: $b * 4;
&[title*='widget-yellow'] {
opacity: 0.3;
box-shadow: $ylwKeyBg 0px 0px $b $b;
}
&[title*='widget-red'] {
opacity: 0.4;
box-shadow: $redKeyBg 0px 0px $b $b;
}
}
}
/**************************************************** SECTIONS */
/************* SYS OVW WIDGETS */
*[title*='Sys Ovw'] {
*[title*='Widget'] {
font-size: 1.4em;
}
*[title*='sys-ok'] {
@include widgetOk();
}
*[title*='post-ring'] {
@include widgetRed();
}
}
/************* ATTITUDE */
*[title*='Attitude'] {
*[title*='RPY'] {
background: black;
padding: 3px;
border-radius: 5px;
.l-control-bar {
display: none;
}
.l-view-section {
top: 0;
}
.gl-plot-axis-area.gl-plot-y {
width: 22px !important;
}
.gl-plot-wrapper-display-area-and-x-axis {
left: 24px !important;
}
}
}
/************* VELOCITY COMPONENT */
*[title*='-not-attained'] {
@include widgetRed();
}
/************* ACCELERATION COMPONENT */
/************* BOOST PHASE WIDGETS */
*[title*='boost-phase-widget'] {
.c-summary-widget {
border-width: 2px;
padding: 5px 0;
&:before,
&:after {
content: '';
display: block;
position: absolute;
}
}
}
*[title*='boost-phase-widget-left'] {
.c-summary-widget {
$c: #999;
align-items: start;
background: rgba($c, 0.1) !important;
border-left: none;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
&:before,
&:after {
top: 25px; right: 0; bottom: 3%; left: 40%;
}
&:before {
@include bgStripes($c: $c, $a: 0.1, $bgsize: 20px, $angle: 0deg);
}
&:after {
@include bgStripes($c: $c, $a: 0.1, $bgsize: 63px, $angle: 0deg);
}
}
}
*[title*='boost-phase-widget-right'] {
.c-summary-widget {
$c: #555;
border-right: none;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
&:before {
//background: deeppink;
@include bgTicks($c: $c, $repeatDir: 'y');
background-size: 100% 45px;
top: 0px; right: 0; bottom: 0; left: 2px;
}
}
}
*[title*='Boost Phase Ring Widgets'] {
*[title*='Ring Widget'] {
//filter: saturate(0.7);
}
*[title*='ring-ok'] {
@include widgetOk();
}
*[title*='bad-ring'] {
@include widgetRed();
}
*[title*='post-ring'] {
@include widgetYellow();
}
}
/************* BOTTOM SYSTEM WIDGETS */
*[title*='system-widget'] {
background: $bgKey !important;
border-width: 2px !important;
justify-content: left !important;
.c-sw__icon {
$m: $interiorMarginSm;
position: absolute;
bottom: $m;
right: $m;
}
}
*[title*="Bottom System Widgets"] {
transform: translateY(-2px);
}
*[title*='system-widget--hero'] {
// Current "tab" in interface
border-top-left-radius: 0;
border-top-right-radius: 0;
border-top: none;
}
*[title*='system-widget--subtle'] {
opacity: 0.7;
}
/**************************************************** INDIVIDUAL ELEMENTS */
/************* PASSENGER NOTICE */
*[title*='passenger-notice'] {
font-size: 1.4em;
.c-sw__icon {
font-size: 2.1em;
margin-right: $interiorMarginLg;
}
}
*[title*='pulse-passenger-notice--nominal'] {
@include pulse($animName: pulseNominal, $dur: 1000ms, $prop: filter, $val0: brightness(1.4), $val100:brightness(1.0), $direction: alternate);
}
*[title*='pulse-passenger-notice--warning'] {
@include pulse($animName: pulseWarning, $dur: 750ms, $prop: background-color, $val0: #aa0000, $val100: #340000, $direction: normal);
}
*[title*='Main Console'] {
$r: $basicCr;
background: $bgKey;
border-radius: $r;
border-bottom: 2px solid rgb(102,102,102);
}
*[title*='Event Time Str'] {
@include heroFont(1.2em);
line-height: .8em;
}
*[title*="Sys Ovw LAD Table"] {
.c-lad-table {
tr {
background-color: black;
color: rgba(white, 0.3);
display: block;
font-weight: bold;
align-items: center;
height: 41px;
border-radius: 5px;
font-size: 0.75em;
margin-bottom: 4px;
overflow: hidden;
padding: 3px;
text-transform: uppercase;
}
thead,
tr td:nth-child(1),
tr td:nth-child(2) {
display: none;
}
td {
display: block;
width: auto;
white-space: normal;
}
}
}

View File

@ -34,3 +34,5 @@
@import "legacy";
@import "legacy-plots";
@import "legacy-messages";
@import "theme-maelstrom";
@import "movie-maelstrom";

View File

@ -26,7 +26,7 @@
@import "constants";
@import "constants-mobile.scss";
//@import "constants-espresso"; // TEMP
@import "constants-snow"; // TEMP
//@import "constants-maelstrom";
//@import "constants-snow"; // TEMP
@import "constants-maelstrom";
@import "mixins";
@import "animations";

View File

@ -0,0 +1,19 @@
/************* FRAMES */
.c-so-view {
&__header {
transform: translateY(3px);
}
&__header__name {
transform: translateY(-2px);
}
&:not(.c-so-view--no-frame) {
$bc: #666;
$bLR: 3px solid transparent;
$br: 20px;
background: none !important;
border: none !important;
padding: 0 !important;
}
}