diff --git a/README.md b/README.md
index 3208f8d..dea76f7 100644
--- a/README.md
+++ b/README.md
@@ -104,6 +104,8 @@ A hook is provided as `/server/scripts/custom.js` to allow customizations to you
Please do not report issues with api.weather.gov being down. It's a new service and not considered fully operational yet. Before reporting an issue or requesting a feature please consider that this is not intended to be a perfect recreation of the WeatherStar 4000, it's a best effort that fits within what's available from the API and within a web browser.
+Note: not all units are converted to metric, if selected. Some text-based products such as warnings are simple text strings provided from the national weather service and thus have baked-in units such as "gusts up to 60 mph." These values will not be converted.
+
## Disclaimer
This web site should NOT be used in life threatening weather situations, or be relied on to inform the public of such situations. The Internet is an unreliable network subject to server and network outages and by nature is not suitable for such mission critical use. If you require such access to NWS data, please consider one of their subscription services. The authors of this web site shall not be held liable in the event of injury, death or property damage that occur as a result of disregarding this warning.
diff --git a/server/scripts/modules/currentweather.mjs b/server/scripts/modules/currentweather.mjs
index 1e8345e..f4ecd89 100644
--- a/server/scripts/modules/currentweather.mjs
+++ b/server/scripts/modules/currentweather.mjs
@@ -8,7 +8,7 @@ import { getWeatherIconFromIconLink } from './icons.mjs';
import WeatherDisplay from './weatherdisplay.mjs';
import { registerDisplay } from './navigation.mjs';
import {
- celsiusToFahrenheit, kphToMph, pascalToInHg, metersToFeet, kilometersToMiles,
+ temperature, windSpeed, pressure, distanceMeters, distanceKilometers,
} from './utils/units.mjs';
// some stations prefixed do not provide all the necessary data
@@ -159,23 +159,32 @@ const shortConditions = (_condition) => {
// format the received data
const parseData = (data) => {
+ // get the unit converter
+ const windConverter = windSpeed();
+ const temperatureConverter = temperature();
+ const metersConverter = distanceMeters();
+ const kilometersConverter = distanceKilometers();
+ const pressureConverter = pressure();
+
const observations = data.features[0].properties;
// values from api are provided in metric
data.observations = observations;
- data.Temperature = Math.round(observations.temperature.value);
- data.TemperatureUnit = 'C';
- data.DewPoint = Math.round(observations.dewpoint.value);
- data.Ceiling = Math.round(observations.cloudLayers[0]?.base?.value ?? 0);
- data.CeilingUnit = 'm.';
- data.Visibility = Math.round(observations.visibility.value / 1000);
- data.VisibilityUnit = ' km.';
- data.WindSpeed = Math.round(observations.windSpeed.value);
+ data.Temperature = temperatureConverter(observations.temperature.value);
+ data.TemperatureUnit = temperatureConverter.units;
+ data.DewPoint = temperatureConverter(observations.dewpoint.value);
+ data.Ceiling = metersConverter(observations.cloudLayers[0]?.base?.value ?? 0);
+ data.CeilingUnit = metersConverter.units;
+ data.Visibility = kilometersConverter(observations.visibility.value);
+ data.VisibilityUnit = kilometersConverter.units;
+ data.Pressure = pressureConverter(observations.barometricPressure.value);
+ data.PressureUnit = pressureConverter.units;
+ data.HeatIndex = temperatureConverter(observations.heatIndex.value);
+ data.WindChill = temperatureConverter(observations.windChill.value);
+ data.WindSpeed = windConverter(observations.windSpeed.value);
data.WindDirection = directionToNSEW(observations.windDirection.value);
- data.Pressure = Math.round(observations.barometricPressure.value);
- data.HeatIndex = Math.round(observations.heatIndex.value);
- data.WindChill = Math.round(observations.windChill.value);
- data.WindGust = Math.round(observations.windGust.value);
- data.WindUnit = 'KPH';
+ data.WindGust = windConverter(observations.windGust.value);
+ data.WindSpeed = windConverter(data.WindSpeed);
+ data.WindUnit = windConverter.units;
data.Humidity = Math.round(observations.relativeHumidity.value);
data.Icon = getWeatherIconFromIconLink(observations.icon);
data.PressureDirection = '';
@@ -186,20 +195,6 @@ const parseData = (data) => {
if (pressureDiff > 150) data.PressureDirection = 'R';
if (pressureDiff < -150) data.PressureDirection = 'F';
- // convert to us units
- data.Temperature = celsiusToFahrenheit(data.Temperature);
- data.TemperatureUnit = 'F';
- data.DewPoint = celsiusToFahrenheit(data.DewPoint);
- data.Ceiling = Math.round(metersToFeet(data.Ceiling) / 100) * 100;
- data.CeilingUnit = 'ft.';
- data.Visibility = kilometersToMiles(observations.visibility.value / 1000);
- data.VisibilityUnit = ' mi.';
- data.WindSpeed = kphToMph(data.WindSpeed);
- data.WindUnit = 'MPH';
- data.Pressure = pascalToInHg(data.Pressure).toFixed(2);
- data.HeatIndex = celsiusToFahrenheit(data.HeatIndex);
- data.WindChill = celsiusToFahrenheit(data.WindChill);
- data.WindGust = kphToMph(data.WindGust);
return data;
};
diff --git a/server/scripts/modules/currentweatherscroll.mjs b/server/scripts/modules/currentweatherscroll.mjs
index ca8655b..0e6fafe 100644
--- a/server/scripts/modules/currentweatherscroll.mjs
+++ b/server/scripts/modules/currentweatherscroll.mjs
@@ -71,7 +71,7 @@ const screens = [
(data) => `Humidity: ${data.Humidity}% Dewpoint: ${data.DewPoint}${degree}${data.TemperatureUnit}`,
// barometric pressure
- (data) => `Barometric Pressure: ${data.Pressure} ${data.PressureDirection}`,
+ (data) => `Barometric Pressure: ${data.Pressure} ${data.PressureUnit} ${data.PressureDirection}`,
// wind
(data) => {
diff --git a/server/scripts/modules/extendedforecast.mjs b/server/scripts/modules/extendedforecast.mjs
index aa5b859..8cbd103 100644
--- a/server/scripts/modules/extendedforecast.mjs
+++ b/server/scripts/modules/extendedforecast.mjs
@@ -8,6 +8,7 @@ import { getWeatherIconFromIconLink } from './icons.mjs';
import { preloadImg } from './utils/image.mjs';
import WeatherDisplay from './weatherdisplay.mjs';
import { registerDisplay } from './navigation.mjs';
+import settings from './settings.mjs';
class ExtendedForecast extends WeatherDisplay {
constructor(navId, elemId) {
@@ -26,7 +27,7 @@ class ExtendedForecast extends WeatherDisplay {
try {
forecast = await json(weatherParameters.forecast, {
data: {
- units: 'us',
+ units: settings.units.value,
},
retryCount: 3,
stillWaiting: () => this.stillWaiting(),
@@ -131,7 +132,7 @@ const shortenExtendedForecastText = (long) => {
[/dense /gi, ''],
[/Thunderstorm/g, 'T\'Storm'],
];
- // run all regexes
+ // run all regexes
const short = regexList.reduce((working, [regex, replace]) => working.replace(regex, replace), long);
let conditions = short.split(' ');
diff --git a/server/scripts/modules/hourly-graph.mjs b/server/scripts/modules/hourly-graph.mjs
index eb7d9d7..e34421f 100644
--- a/server/scripts/modules/hourly-graph.mjs
+++ b/server/scripts/modules/hourly-graph.mjs
@@ -38,7 +38,7 @@ class HourlyGraph extends WeatherDisplay {
const skyCover = data.map((d) => d.skyCover);
this.data = {
- skyCover, temperature, probabilityOfPrecipitation,
+ skyCover, temperature, probabilityOfPrecipitation, temperatureUnit: data[0].temperatureUnit,
};
this.setStatus(STATUS.loaded);
@@ -107,6 +107,9 @@ class HourlyGraph extends WeatherDisplay {
// set the image source
this.image.src = canvas.toDataURL();
+ // change the units in the header
+ this.elem.querySelector('.temperature').innerHTML = `Temperature ${String.fromCharCode(176)}${this.data.temperatureUnit}`;
+
super.drawCanvas();
this.finishDraw();
}
diff --git a/server/scripts/modules/hourly.mjs b/server/scripts/modules/hourly.mjs
index a04f59d..88791e4 100644
--- a/server/scripts/modules/hourly.mjs
+++ b/server/scripts/modules/hourly.mjs
@@ -3,7 +3,7 @@
import STATUS from './status.mjs';
import { DateTime, Interval, Duration } from '../vendor/auto/luxon.mjs';
import { json } from './utils/fetch.mjs';
-import { celsiusToFahrenheit, kilometersToMiles } from './utils/units.mjs';
+import { temperature as temperatureUnit, distanceKilometers } from './utils/units.mjs';
import { getHourlyIcon } from './icons.mjs';
import { directionToNSEW } from './utils/calc.mjs';
import WeatherDisplay from './weatherdisplay.mjs';
@@ -56,6 +56,9 @@ class Hourly extends WeatherDisplay {
const list = this.elem.querySelector('.hourly-lines');
list.innerHTML = '';
+ // get a unit converter
+ const temperatureConverter = temperatureUnit();
+
const startingHour = DateTime.local();
const lines = this.data.map((data, index) => {
@@ -66,7 +69,7 @@ class Hourly extends WeatherDisplay {
fillValues.hour = formattedHour;
// temperatures, convert to strings with no decimal
- const temperature = Math.round(data.temperature).toString().padStart(3);
+ const temperature = temperatureConverter(data.temperature).toString().padStart(3);
const feelsLike = Math.round(data.apparentTemperature).toString().padStart(3);
fillValues.temp = temperature;
// only plot apparent temperature if there is a difference
@@ -132,6 +135,11 @@ class Hourly extends WeatherDisplay {
// extract specific values from forecast and format as an array
const parseForecast = async (data) => {
+ // get unit converters
+ const temperatureConverter = temperatureUnit();
+ const distanceConverter = distanceKilometers();
+
+ // parse data
const temperature = expand(data.temperature.values);
const apparentTemperature = expand(data.apparentTemperature.values);
const windSpeed = expand(data.windSpeed.values);
@@ -145,9 +153,11 @@ const parseForecast = async (data) => {
const icons = await determineIcon(skyCover, weather, iceAccumulation, probabilityOfPrecipitation, snowfallAmount, windSpeed);
return temperature.map((val, idx) => ({
- temperature: celsiusToFahrenheit(temperature[idx]),
- apparentTemperature: celsiusToFahrenheit(apparentTemperature[idx]),
- windSpeed: kilometersToMiles(windSpeed[idx]),
+ temperature: temperatureConverter(temperature[idx]),
+ temperatureUnit: temperatureConverter.units,
+ apparentTemperature: temperatureConverter(apparentTemperature[idx]),
+ windSpeed: distanceConverter(windSpeed[idx]),
+ windUnit: distanceConverter.units,
windDirection: directionToNSEW(windDirection[idx]),
probabilityOfPrecipitation: probabilityOfPrecipitation[idx],
skyCover: skyCover[idx],
diff --git a/server/scripts/modules/latestobservations.mjs b/server/scripts/modules/latestobservations.mjs
index 98cba31..2d44c82 100644
--- a/server/scripts/modules/latestobservations.mjs
+++ b/server/scripts/modules/latestobservations.mjs
@@ -3,9 +3,10 @@ import { distance as calcDistance, directionToNSEW } from './utils/calc.mjs';
import { json } from './utils/fetch.mjs';
import STATUS from './status.mjs';
import { locationCleanup } from './utils/string.mjs';
-import { celsiusToFahrenheit, kphToMph } from './utils/units.mjs';
+import { temperature, windSpeed } from './utils/units.mjs';
import WeatherDisplay from './weatherdisplay.mjs';
import { registerDisplay } from './navigation.mjs';
+import settings from './settings.mjs';
class LatestObservations extends WeatherDisplay {
constructor(navId, elemId) {
@@ -64,14 +65,22 @@ class LatestObservations extends WeatherDisplay {
// sort array by station name
const sortedConditions = conditions.sort((a, b) => ((a.Name < b.Name) ? -1 : 1));
- this.elem.querySelector('.column-headers .temp.english').classList.add('show');
- this.elem.querySelector('.column-headers .temp.metric').classList.remove('show');
+ if (settings.units.value === 'us') {
+ this.elem.querySelector('.column-headers .temp.english').classList.add('show');
+ this.elem.querySelector('.column-headers .temp.metric').classList.remove('show');
+ } else {
+ this.elem.querySelector('.column-headers .temp.english').classList.remove('show');
+ this.elem.querySelector('.column-headers .temp.metric').classList.add('show');
+ }
+ // get unit converters
+ const windConverter = windSpeed();
+ const temperatureConverter = temperature();
const lines = sortedConditions.map((condition) => {
const windDirection = directionToNSEW(condition.windDirection.value);
- const Temperature = Math.round(celsiusToFahrenheit(condition.temperature.value));
- const WindSpeed = Math.round(kphToMph(condition.windSpeed.value));
+ const Temperature = temperatureConverter(condition.temperature.value);
+ const WindSpeed = windConverter(condition.windSpeed.value);
const fill = {
location: locationCleanup(condition.city).substr(0, 14),
@@ -94,6 +103,8 @@ class LatestObservations extends WeatherDisplay {
linesContainer.innerHTML = '';
linesContainer.append(...lines);
+ // update temperature unit header
+
this.finishDraw();
}
}
@@ -122,8 +133,8 @@ const getStations = async (stations) => {
const data = await json(`https://api.weather.gov/stations/${station.id}/observations/latest`, { retryCount: 1, stillWaiting: () => this.stillWaiting() });
// test for temperature, weather and wind values present
if (data.properties.temperature.value === null
- || data.properties.textDescription === ''
- || data.properties.windSpeed.value === null) return false;
+ || data.properties.textDescription === ''
+ || data.properties.windSpeed.value === null) return false;
// format the return values
return {
...data.properties,
diff --git a/server/scripts/modules/localforecast.mjs b/server/scripts/modules/localforecast.mjs
index 3528b20..714e916 100644
--- a/server/scripts/modules/localforecast.mjs
+++ b/server/scripts/modules/localforecast.mjs
@@ -4,6 +4,7 @@ import STATUS from './status.mjs';
import { json } from './utils/fetch.mjs';
import WeatherDisplay from './weatherdisplay.mjs';
import { registerDisplay } from './navigation.mjs';
+import settings from './settings.mjs';
class LocalForecast extends WeatherDisplay {
constructor(navId, elemId) {
@@ -61,7 +62,7 @@ class LocalForecast extends WeatherDisplay {
try {
return await json(weatherParameters.forecast, {
data: {
- units: 'us',
+ units: settings.units.value,
},
retryCount: 3,
stillWaiting: () => this.stillWaiting(),
diff --git a/server/scripts/modules/regionalforecast.mjs b/server/scripts/modules/regionalforecast.mjs
index 15d89b1..82d5f27 100644
--- a/server/scripts/modules/regionalforecast.mjs
+++ b/server/scripts/modules/regionalforecast.mjs
@@ -4,7 +4,7 @@
import STATUS from './status.mjs';
import { distance as calcDistance } from './utils/calc.mjs';
import { json } from './utils/fetch.mjs';
-import { celsiusToFahrenheit } from './utils/units.mjs';
+import { temperature as temperatureUnit } from './utils/units.mjs';
import { getWeatherRegionalIconFromIconLink } from './icons.mjs';
import { preloadImg } from './utils/image.mjs';
import { DateTime } from '../vendor/auto/luxon.mjs';
@@ -59,7 +59,7 @@ class RegionalForecast extends WeatherDisplay {
const regionalCities = [];
combinedCities.forEach((city) => {
if (city.lat > minMaxLatLon.minLat && city.lat < minMaxLatLon.maxLat
- && city.lon > minMaxLatLon.minLon && city.lon < minMaxLatLon.maxLon - 1) {
+ && city.lon > minMaxLatLon.minLon && city.lon < minMaxLatLon.maxLon - 1) {
// default to 1 for cities loaded from RegionalCities, use value calculate above for remaining stations
const targetDist = city.targetDistance || 1;
// Only add the city as long as it isn't within set distance degree of any other city already in the array.
@@ -71,6 +71,9 @@ class RegionalForecast extends WeatherDisplay {
}
});
+ // get a unit converter
+ const temperatureConverter = temperatureUnit();
+
// get regional forecasts and observations (the two are intertwined due to the design of api.weather.gov)
const regionalDataAll = await Promise.all(regionalCities.map(async (city) => {
try {
@@ -93,7 +96,7 @@ class RegionalForecast extends WeatherDisplay {
// format the observation the same as the forecast
const regionalObservation = {
daytime: !!/\/day\//.test(observation.icon),
- temperature: celsiusToFahrenheit(observation.temperature.value),
+ temperature: temperatureConverter(observation.temperature.value),
name: utils.formatCity(city.city),
icon: observation.icon,
x: cityXY.x,
diff --git a/server/scripts/modules/settings.mjs b/server/scripts/modules/settings.mjs
index d94ceb3..6a809de 100644
--- a/server/scripts/modules/settings.mjs
+++ b/server/scripts/modules/settings.mjs
@@ -18,6 +18,10 @@ const init = () => {
[1.25, 'Slow'],
[1.5, 'Very Slow'],
]);
+ settings.units = new Setting('units', 'Units', 'select', 'us', unitChange, true, [
+ ['us', 'US'],
+ ['si', 'Metric'],
+ ]);
// generate html objects
const settingHtml = Object.values(settings).map((d) => d.generate());
@@ -47,4 +51,13 @@ const kioskChange = (value) => {
}
};
+const unitChange = () => {
+ // reload the data at the top level to refresh units
+ // after the initial load
+ if (unitChange.firstRunDone) {
+ window.location.reload();
+ }
+ unitChange.firstRunDone = true;
+};
+
export default settings;
diff --git a/server/scripts/modules/travelforecast.mjs b/server/scripts/modules/travelforecast.mjs
index 8eaabf7..920ab2c 100644
--- a/server/scripts/modules/travelforecast.mjs
+++ b/server/scripts/modules/travelforecast.mjs
@@ -5,6 +5,7 @@ import { getWeatherRegionalIconFromIconLink } from './icons.mjs';
import { DateTime } from '../vendor/auto/luxon.mjs';
import WeatherDisplay from './weatherdisplay.mjs';
import { registerDisplay } from './navigation.mjs';
+import settings from './settings.mjs';
class TravelForecast extends WeatherDisplay {
constructor(navId, elemId, defaultActive) {
@@ -34,7 +35,11 @@ class TravelForecast extends WeatherDisplay {
try {
// get point then forecast
if (!city.point) throw new Error('No pre-loaded point');
- const forecast = await json(`https://api.weather.gov/gridpoints/${city.point.wfo}/${city.point.x},${city.point.y}/forecast`);
+ const forecast = await json(`https://api.weather.gov/gridpoints/${city.point.wfo}/${city.point.x},${city.point.y}/forecast`, {
+ data: {
+ units: settings.units.value,
+ },
+ });
// determine today or tomorrow (shift periods by 1 if tomorrow)
const todayShift = forecast.properties.periods[0].isDaytime ? 0 : 1;
// return a pared-down forecast
diff --git a/server/scripts/modules/utils/setting.mjs b/server/scripts/modules/utils/setting.mjs
index 7a8da59..2a26970 100644
--- a/server/scripts/modules/utils/setting.mjs
+++ b/server/scripts/modules/utils/setting.mjs
@@ -24,6 +24,10 @@ class Setting {
if (type === 'select' && urlValue !== undefined) {
urlState = parseFloat(urlValue);
}
+ if (type === 'select' && urlValue !== undefined && Number.isNaN(urlState)) {
+ // couldn't parse as a float, store as a string
+ urlState = urlValue;
+ }
// get existing value if present
const storedValue = urlState ?? this.getFromLocalStorage();
@@ -59,7 +63,11 @@ class Setting {
this.values.forEach(([value, text]) => {
const option = document.createElement('option');
- option.value = value.toFixed(2);
+ if (typeof value === 'number') {
+ option.value = value.toFixed(2);
+ } else {
+ option.value = value;
+ }
option.innerHTML = text;
select.append(option);
@@ -108,6 +116,10 @@ class Setting {
selectChange(e) {
// update the value
this.myValue = parseFloat(e.target.value);
+ if (Number.isNaN(this.myValue)) {
+ // was a string, store as such
+ this.myValue = e.target.value;
+ }
this.storeToLocalStorage(this.myValue);
// call the change action
@@ -168,7 +180,7 @@ class Setting {
selectHighlight(newValue) {
// set the dropdown to the provided value
this.element.querySelectorAll('option').forEach((elem) => {
- elem.selected = newValue.toFixed(2) === elem.value;
+ elem.selected = (newValue?.toFixed?.(2) === elem.value) || (newValue === elem.value);
});
}
diff --git a/server/scripts/modules/utils/units.mjs b/server/scripts/modules/utils/units.mjs
index fea90b4..e612fe2 100644
--- a/server/scripts/modules/utils/units.mjs
+++ b/server/scripts/modules/utils/units.mjs
@@ -1,5 +1,8 @@
+// get the settings for units
+import settings from '../settings.mjs';
// *********************************** unit conversions ***********************
+// round 2 provided for lat/lon formatting
const round2 = (value, decimals) => Math.trunc(value * 10 ** decimals) / 10 ** decimals;
const kphToMph = (Kph) => Math.round(Kph / 1.609_34);
@@ -8,11 +11,98 @@ const kilometersToMiles = (Kilometers) => Math.round(Kilometers / 1.609_34);
const metersToFeet = (Meters) => Math.round(Meters / 0.3048);
const pascalToInHg = (Pascal) => round2(Pascal * 0.000_295_3, 2);
+// each module/page/slide creates it's own unit converter as needed by providing the base units available
+// the factory function then returns an appropriate converter or pass-thru function for use on the page
+
+const windSpeed = (defaultUnit = 'si') => {
+ // default to passthru
+ let converter = (passthru) => Math.round(passthru);
+ // change the converter if there is a mismatch
+ if (defaultUnit !== settings.units.value) {
+ converter = kphToMph;
+ }
+ // append units
+ if (settings.units.value === 'si') {
+ converter.units = 'kph';
+ } else {
+ converter.units = 'MPH';
+ }
+ return converter;
+};
+
+const temperature = (defaultUnit = 'si') => {
+ // default to passthru
+ let converter = (passthru) => Math.round(passthru);
+ // change the converter if there is a mismatch
+ if (defaultUnit !== settings.units.value) {
+ converter = celsiusToFahrenheit;
+ }
+ // append units
+ if (settings.units.value === 'si') {
+ converter.units = 'C';
+ } else {
+ converter.units = 'F';
+ }
+ return converter;
+};
+
+const distanceMeters = (defaultUnit = 'si') => {
+ // default to passthru
+ let converter = (passthru) => Math.round(passthru);
+ // change the converter if there is a mismatch
+ if (defaultUnit !== settings.units.value) {
+ // rounded to the nearest 100 (ceiling)
+ converter = (value) => Math.round(metersToFeet(value) / 100) * 100;
+ }
+ // append units
+ if (settings.units.value === 'si') {
+ converter.units = 'm.';
+ } else {
+ converter.units = 'ft.';
+ }
+ return converter;
+};
+
+const distanceKilometers = (defaultUnit = 'si') => {
+ // default to passthru
+ let converter = (passthru) => Math.round(passthru / 1000);
+ // change the converter if there is a mismatch
+ if (defaultUnit !== settings.units.value) {
+ converter = (value) => Math.round(kilometersToMiles(value) / 1000);
+ }
+ // append units
+ if (settings.units.value === 'si') {
+ converter.units = ' km.';
+ } else {
+ converter.units = ' mi.';
+ }
+ return converter;
+};
+
+const pressure = (defaultUnit = 'si') => {
+ // default to passthru (millibar)
+ let converter = (passthru) => Math.round(passthru / 100);
+ // change the converter if there is a mismatch
+ if (defaultUnit !== settings.units.value) {
+ converter = (value) => pascalToInHg(value).toFixed(2);
+ }
+ // append units
+ if (settings.units.value === 'si') {
+ converter.units = ' mbar';
+ } else {
+ converter.units = ' in.hg';
+ }
+ return converter;
+};
+
export {
- kphToMph,
- celsiusToFahrenheit,
- kilometersToMiles,
- metersToFeet,
- pascalToInHg,
+ // unit conversions
+ windSpeed,
+ temperature,
+ distanceMeters,
+ distanceKilometers,
+ pressure,
+
+ // formatter
round2,
};
diff --git a/views/index.ejs b/views/index.ejs
index 8028441..3f6935b 100644
--- a/views/index.ejs
+++ b/views/index.ejs
@@ -10,7 +10,7 @@
-
+
diff --git a/ws4kp.code-workspace b/ws4kp.code-workspace
index ab71c61..36766ab 100644
--- a/ws4kp.code-workspace
+++ b/ws4kp.code-workspace
@@ -22,6 +22,7 @@
"devbridge",
"gifs",
"ltrim",
+ "mbar",
"Noaa",
"nosleep",
"Pngs",