Merge branch 'espruino:master' into promenu-0.11

master
Tom Wallroth 2025-01-02 10:24:56 +01:00 committed by GitHub
commit c9c9003014
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 442 additions and 102 deletions

View File

@ -14,4 +14,4 @@
}
})
};
}) // must not have a semi-colon!
})

View File

@ -24,4 +24,4 @@
]
};
return ci;
}) // must not have a semi-colon!
})

View File

@ -46,4 +46,4 @@
]
};
return ci;
}) // must not have a semi-colon!
})

View File

@ -0,0 +1,2 @@
0.01: Initial commit
0.02: Added Alt modes

38
apps/dsky_clock/README.md Normal file
View File

@ -0,0 +1,38 @@
# DSKY Clock
This is a clockface inspired by the Apollo DSKY interface.
## Features
- battery level indicator (PROG indicator)
- month (VERB indicator)
- date (NOUN indicator)
- Current local time (DATA 1)
- UTC time (DATA 2)
- Step counter (DATA 3)
Indicator lights are:
- COMP ACTY (GPS/HRM active)
- MSG (Messages waiting)
- LOCK (Screen is locked)
- BT (Bluetooth is disconnected)
- BATT (Low battery or battery charging)
- ALARM (Alarm is set)
- STEP (Reached STEP goal))
----
## Alt Modes
Swipe left/right to switch between different PROGRAM modes.
- HRM (BPM/Confidence)
- GPS (Latitude/Longitude/Speed)
- Weather (Humidity/Rain/Temperature/Wind/Condition Code)
- Accelerometer (X/Y/Z)
- Compass (HEADING)
In the interests of usability these change the "LIGHT" on the left side to show the current mode.
----
This is my first watch face, may add features and customization later.
## Creator
Written by Carl Chan | [github](https://github.com/carlchan)

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwkIkQAFkIEDiQMGABUAiQtIu1nu9wgETC40QDIIAHu4ABC4MCkURiVCAAMimQXJswABAgMDC4IADLIQLBBAYcHF4QXSg4XDiEBgIXCkIXCAQgADgwvFBwIXFF4sGuwXHI4cxCIQ4CF5gXCR4ZfJF5SPXI4S4EFgQGBsAvMdAikCAwJ5BF5YXJu7vMI4RABI4gvCmQXJDIQEIL5YRBgxHDAgR3D7vd6gCB6QXEHwIXDCoQGBC4YACC4sGs5fDAgQvE6lEpvd6YXECwkGAgQvFrovDU4QXJL4pHIRQtnR4oXGkIlCAAK6BDwgvPgwEDSIgXLgynBAYhHMC4UHOQIWBAIMHBAIXCmXdqioBC4UyIoYXBeQNmCoJOCF4VVCwJHGH4UHGAQXEF4JHFF4ZHEAYJHEU5RCBI4SoBC4JHFpoBCC4jWDdoaPFiIADiS/FABIXIL4QvCRwK/IisAiEAgIXBL4ZzCPIZfDCAIVBAAIXCU4gXEX4xfJBwNmXoS/GC40yd4hcCIoa/EF40xdYS9BMQNnC5ovER4JFDU6K/NgJHHXoQBBSQbzCI5C/Cg9mAAQaBAYSnNNwJcBMANwAIQXKlS/EbIIBDC4UDa5gvBMAYvFAAsQI4bsCPQYFBC5MAC4RcCCgZiCBQNTXAIXEiMikJOCiBUEBAcTA="))

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

381
apps/dsky_clock/app.js Normal file
View File

@ -0,0 +1,381 @@
//Init
var Layout = require("Layout");
require("Font7x11Numeric7Seg").add(Graphics);
require("FontTeletext5x9Ascii").add(Graphics);
const Light_on='#fff';
const Light_off='#554';
const Light_warn='#f90';
const Light_COMPACTY='#0F0';
const Light_width=43;
const Light_height=25;
const EL7_height=30;
const LightFont='Teletext5x9Ascii';
const DataFont='7x11Numeric7Seg:2';
var mode = 0;
if (global.WIDGETS) {require("widget_utils").swipeOn();} // If `dsky_clock` was fast loaded into we seemingly need to hide the widgets before setting the layout so elements are not moved down.
var layout = new Layout(
{type:"h", c:[
{type:"",width:6},
{ type:"v", c: [
{type:"txt", font:LightFont, col:"#000", bgCol:"#555", id:'L1', label:"UPLINK\nACTY", width:Light_width, height:Light_height},
{type:"txt", font:LightFont, col:"#000", bgCol:"#555", id:'L2', label:"TEMP", width:Light_width, height:Light_height },
{type:"txt", font:LightFont, col:"#000", bgCol:"#555", id:'L3', label:"GIMBAL\nLOCK", width:Light_width, height:Light_height },
{type:"txt", font:LightFont, col:"#000", bgCol:"#555", id:'L4', label:"STBY", width:Light_width, height:Light_height },
{type:"txt", font:LightFont, col:"#000", bgCol:"#555", id:'L5', label:"PROG", width:Light_width, height:Light_height },
{type:"txt", font:LightFont, col:"#000", bgCol:"#eee", id:'L6', label:"OPR ERR", width:Light_width, height:Light_height },
]},
{ type:"", width:20},
{ type:"v", c: [
{type:"",height:2},
{type:"h", c: [
{type:"", width:50},{type:"txt", font:"6x8", col:"#000",bgCol:"#0F0", label:"PROG", width:25, height:10},
]},
{type:"h", c: [
{type:"",width:10},
{type:"txt", font:"6x8", col:"#000", bgCol:"#000", id:"COMPACTY", label:"COMP\nACTY", width:26, height:26 },
{type:"",width:17},
{type:"txt", font:DataFont, col:"#0F0", bgCol:"#000",label:"00", id:"PROG", fillx:1, height:EL7_height },
]},
{type:"",height:1},
{type:"h", c: [
{type:"txt", font:"6x8", col:"#000", bgCol:"#0F0",label:"VERB", width:25, height:10},
{type:"",width:30},
{type:"txt", font:"6x8", col:"#000",bgCol:"#0F0",label:"NOUN", width:25, height:10},
]},
{type:"h", c: [
{type:"txt", font:DataFont, col:"#0F0", bgCol:"#000", label:"00", id:"VERB", fillx:1, height:EL7_height},
{type:"txt", font:DataFont, col:"#0F0", bgCol:"#000", label:"00", id:"NOUN", fillx:1, height:EL7_height},
]},
{ type:"",bgCol:'#070', width:80, height:2 },
{type:"txt", font:DataFont, col:"#0F0", bgCol:"#000", label:"00000", id:"R1", halign:1, fillx:1, height:EL7_height},
{type:"txt", font:DataFont, col:"#0F0", bgCol:"#000", label:"00000", id:"R2", halign:1, fillx:1, height:EL7_height},
{type:"txt", font:DataFont, col:"#0F0", bgCol:"#000", label:"00000", id:"R3", halign:1, fillx:1, height:EL7_height},
]},
{type:"",width:5},
],
lazy:true},
{btns:[
{label:"", cb: Bangle.showLauncher}
], lazy:true});
layout.update();
//support functioe_ns
function getWeather() {
var weather = {};
try {
weather = require("Storage").readJSON('weather.json', 1).weather;
} catch(e) {
return {};
}
return weather;
}
function getdatetime(){
var datetime = [];
var d = new Date();
// var offsets = require("Storage").readJSON("worldclock.settings.json") || [];
// var meridian = require("locale").meridian(d);
datetime.clock = require("locale").time(d, 1);
datetime.month = d.getMonth()+1;
datetime.day = d.getDate();
datetime.localtime=String(d.getHours()).padStart(2,'0')+String(d.getMinutes()).padStart(2,'0');
let utchour=((d.getHours()+(Math.round(d.getTimezoneOffset()/60))) % 24);
datetime.utctime=String(utchour).padStart(2,'0')+String(d.getMinutes()).padStart(2,'0');
return datetime;
}
function getSteps(){
let steps=Bangle.getHealthStatus("day").steps;
steps = typeof steps !== 'undefined' ? steps:0;
return steps;
}
function getStepGoal(){
let stepGoal = (require("Storage").readJSON("health.json",1)||10000).stepGoal;
stepGoal = typeof stepGoal !== 'undefined' ? stepGoal:10000;
return stepGoal;
}
function isAlarmSet(){
let alarmStatus = (require('Storage').readJSON('sched.json',1)||[]).some(alarm=>alarm.on);
return alarmStatus;
}
function isMessagesNotify(){
if (require("Storage").read("messages.json")!==undefined) {
return true;
} else {
return false;
}
}
function getHRM(){
let hrm=Bangle.getHealthStatus('last');
hrm = typeof hrm !== 'undefined' ? hrm:0;
return hrm;
}
function isBTConnected(){
return NRF.getSecurityStatus().connected;
}
function getBattery(){
let battlevel = E.getBattery();
if (Bangle.isCharging()) {
battlevel = -1;
} else if (battlevel >= 100) {
battlevel = 99;
}
battlevel=String(battlevel);
return battlevel;
}
function isActive(){
if (Bangle.isCompassOn() || Bangle.isGPSOn() || Bangle.isHRMOn() || Bangle.isBarometerOn() ) {
return true;
} else {
return false;
}
}
function setLight(id,label,check,onColour,offColour){
// print('setlight:',id); //debug
layout.clear(layout[id]);
onColour = typeof onColour !== 'undefined' ? onColour:Light_on;
offColour = typeof offColour !== 'undefined' ? offColour:Light_off;
if (label !== '') {
layout[id].label=label;
}
if (check) {
layout[id].bgCol=onColour;
} else {
layout[id].bgCol=offColour;
}
layout.render(layout[id]);
}
function setDATA(id,label) {
layout.clear(layout[id]);
let data='-----';
let sign='';
try {
if (!isNaN(label)) {
if (label < 0) {
label=Math.abs(label);
sign='-';
}
data=String(String(label).toString(16)).toUpperCase().padStart(5,'0').substring(0,5);
data=sign+data;
}
} catch(e) {
data='-----';
}
layout[id].label=data;
layout.render(layout[id]);
}
function setWORD(id,label){
layout.clear(layout[id]);
let data='--';
if (!isNaN(label)) {
data=String(String(label).toString(16)).toUpperCase().padStart(2,'0').substring(0,2);
}
// print(id, data); //debug
layout[id].label=data;
layout.render(layout[id]);
}
function draw_bg(){
g.setColor('#666');
g.fillRect(0,0,176,176);
g.setColor('#000');
g.fillRect(69,2,172,174);
g.fillCircle(59,10,5);
g.fillCircle(59,166,5);
}
// actual display
function drawMain(){
let datetime=getdatetime();
setDATA('R1',datetime.localtime);
setDATA('R2',datetime.utctime);
setDATA('R3',getSteps());
setWORD('PROG',getBattery());
setWORD('VERB',datetime.month);
setWORD('NOUN',datetime.day);
setLight('COMPACTY','',isActive(),Light_COMPACTY);
setLight('L1','MSG',isMessagesNotify());
setLight('L2','LOCK',Bangle.isLocked());
setLight('L3','BT',!isBTConnected(),Light_warn);
setLight('L4','BATT',(getBattery()<=20),Light_warn);
setLight('L5','ALARM',isAlarmSet(),Light_warn);
setLight('L6','STEP',(getSteps()>=getStepGoal()),'#0a0');
// layout.setUI();
layout.forgetLazyState();
layout.render();
queueDraw();
}
////// ALT modes /////
var AltDrawTimer;
function drawAlt(mode) {
if (AltDrawTimer) clearTimeout(AltDrawTimer);
mode = typeof mode !== 'undefined' ? mode:0;
mode=Math.abs(mode);
// print('drawAlt: ', mode); // debug
// Show mode in PROG
setWORD('PROG',mode);
setWORD('NOUN','');
setWORD('VERB','');
// Disable Battery warning light in to show PROG no longer shows battery level
setLight('L4','BATT',false);
setDATA('R1');
setDATA('R2');
setDATA('R3');
switch (mode) {
case 1:
setLight('L6','HRM',true);
mode_HRM();
break;
case 2:
setLight('L6','TEMP',true);
mode_weather();
break;
case 3:
setLight('L6','GPS',true);
mode_GPS();
break;
case 4:
setLight('L6','ACCEL',true);
mode_accel();
break;
case 5:
setLight('L6','HDG',true);
mode_compass();
break;
default:
drawMain();
}
layout.render();
}
function mode_HRM() {
setLight('COMPACTY','',true,Light_COMPACTY);
AltDrawTimer = setTimeout( function() {
Bangle.setHRMPower(true, 'dsky_clock');
let hrm=getHRM();
setDATA('R1',hrm.bpm);
setDATA('R2',hrm.bpmConfidence);
setDATA('R3',getSteps());
mode_HRM();
}, 5000);
Bangle.setHRMPower(false);
}
function mode_weather() {
let weather=getWeather();
try {
weather.temp = Math.round(weather.temp-273.15);
setDATA('R1',weather.temp);
setDATA('R2',weather.hum);
setDATA('R3',weather.code);
setWORD('NOUN',weather.hum);
setWORD('VERB',weather.rain);
} catch(e) {
setDATA('R1','-----');
setDATA('R2','-----');
setDATA('R3','-----');
setDATA('R1','--');
setDATA('R1','--');
}
}
function mode_compass() {
AltDrawTimer = setTimeout ( function() {
setLight('COMPACTY','',true,Light_COMPACTY); //isCompassOn seems to be incorrect?
Bangle.setCompassPower(1);
let compass=Bangle.getCompass();
setDATA('R1',compass.heading);
setDATA('R2');
setDATA('R3');
mode_compass();
}, 200);
Bangle.setCompassPower(0);
}
function mode_GPS() {
setLight('COMPACTY','',true,Light_COMPACTY);
AltDrawTimer = setTimeout( function() {
Bangle.setGPSPower(1,'dsky_clock');
let gps=Bangle.getGPSFix();
setWORD('NOUN',gps.fix);
setWORD('VERB',gps.satellites);
setDATA('R1',gps.lat);
setDATA('R2',gps.lon);
setDATA('R3',gps.speed);
mode_GPS();
}, 5000);
Bangle.setGPSPower(0);
}
function mode_accel() {
AltDrawTimer = setTimeout( function() {
setLight('COMPACTY','',isActive(),Light_COMPACTY);
let accel=Bangle.getAccel();
setDATA('R1',accel.x);
setDATA('R2',accel.y);
setDATA('R3',accel.z);
mode_accel();
}, 100);
}
//////////// Main
var drawTimeout;
// schedule a draw for the next minute
function queueDraw() {
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
mode = 0;
if (AltDrawTimer) clearTimeout(AltDrawTimer);
drawMain();
}, 60000 - (Date.now() % 60000));
}
Bangle.on('lock',on=>{
mode = 0;
drawMain(); // draw immediately
});
Bangle.on("message",function() { setLight('COMPACTY','',isActive(),Light_COMPACTY);});
Bangle.on('charging',drawMain);
NRF.on('connect',function() { setLight('L3','BT',!isBTConnected(),Light_warn); });
NRF.on('disconnect',function() { setLight('L3','BT',!isBTConnected(),Light_warn); });
Bangle.on('swipe', function(directionLR) {
if (directionLR == 1) {
mode=mode-1;
}
if (directionLR == -1) {
mode=mode+1;
}
if (mode < 0 ) { mode=5; }
mode=(mode % 6);
drawAlt(mode);
});
g.clear();
draw_bg();
drawMain();
Bangle.CLOCK = 1;
Bangle.loadWidgets(); // loading widgets after drawing the layout in `drawMain()` to display the app UI ASAP.
require("widget_utils").swipeOn(); // hide widgets, make them visible with a swipe

View File

@ -0,0 +1,16 @@
{ "id": "dsky_clock",
"name": "DSKY Clock",
"icon": "app-icon.png",
"screenshots": [{"url":"screenshot1.png"}],
"version": "0.02",
"description": "A clockface inspired by the Apollo DSKY interface.",
"tags": "clock",
"type": "clock",
"supports":["BANGLEJS2"],
"readme": "README.md",
"allow_emulator": true,
"storage": [
{"name":"dsky_clock.app.js","url":"app.js"},
{"name":"dsky_clock.img","url":"app-icon.js","evaluate":true}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -39,4 +39,4 @@
}
}
});
})/*(load)/**/
})

View File

@ -124,104 +124,6 @@ var KNOWN_WARNINGS = [
`In locale test, long time format might not work in some apps if it is not "%HH:%MM:%SS"`,
`In locale wae_CH, short time format might not work in some apps if it is not "%HH:%MM"`,
`In locale test, short time format might not work in some apps if it is not "%HH:%MM"`,
"App a_dndtoggle file a_dndtoggle.settings.js should be evaluated as a function but doesn't end in ')'",
"App activepedom file activepedom.settings.js should be evaluated as a function but doesn't end in ')'",
"App agpsdata file agpsdata.settings.js should be evaluated as a function but doesn't end in ')'",
"App alarm file alarm.settings.js should be evaluated as a function but doesn't end in ')'",
"App andark file andark.settings.js should be evaluated as a function but doesn't end in ')'",
"App antonclkplus file antonclkplus.settings.js should be evaluated as a function but doesn't end in ')'",
"App banglexercise file banglexercise.settings.js should be evaluated as a function but doesn't end in ')'",
"App barclock file barclock.settings.js should be evaluated as a function but doesn't end in ')'",
"App berlinc file berlinc.settings.js should be evaluated as a function but doesn't end in ')'",
"App bikespeedo file bikespeedo.settings.js should be evaluated as a function but doesn't end in ')'",
"App blc file blc.settings.js should be evaluated as a function but doesn't end in ')'",
"App boxclk file boxclk.settings.js should be evaluated as a function but doesn't end in ')'",
"App bthome file bthome.clkinfo.js should be evaluated as a function but doesn't end in ')'",
"App bthrm file bthrm.settings.js should be evaluated as a function but doesn't end in ')'",
"App carcrazy file carcrazy.settings.js should be evaluated as a function but doesn't end in ')'",
"App chimer file chimer.settings.js should be evaluated as a function but doesn't end in ')'",
"App circlesclock file circlesclock.settings.js should be evaluated as a function but doesn't end in ')'",
"App clicompleteclk file clicompleteclk.settings.js should be evaluated as a function but doesn't end in ')'",
"App clkinfocal file clkinfocal.settings.js should be evaluated as a function but doesn't end in ')'",
"App clkinfogps file gps.clkinfo.js should be evaluated as a function but doesn't end in ')'",
"App clkinfogpsspeed file clkinfogpsspeed.clkinfo.js should be evaluated as a function but doesn't end in ')'",
"App clkinfom file ram.clkinfo.js should be evaluated as a function but doesn't end in ')'",
"App clkinfomag file clkinfomag.clkinfo.js should be evaluated as a function but doesn't end in ')'",
"App clkinfostopw file stopw.clkinfo.js should be evaluated as a function but doesn't end in ')'",
"App clockcal file clockcal.settings.js should be evaluated as a function but doesn't end in ')'",
"App cogclock file cogclock.settings.js should be evaluated as a function but doesn't end in ')'",
"App counter2 file counter2.settings.js should be evaluated as a function but doesn't end in ')'",
"App cprassist file cprassist.settings.js should be evaluated as a function but doesn't end in ')'",
"App dane_tcr file dane_tcr.settings.js should be evaluated as a function but doesn't end in ')'",
"App dragboard file dragboard.settings.js should be evaluated as a function but doesn't end in ')'",
"App draguboard file draguboard.settings.js should be evaluated as a function but doesn't end in ')'",
"App drained file drained.settings.js should be evaluated as a function but doesn't end in ')'",
"App drinkcounter file drinkcounter.settings.js should be evaluated as a function but doesn't end in ')'",
"App dtlaunch file dtlaunch.settings.js should be evaluated as a function but doesn't end in ')'",
"App ffcniftyb file ffcniftyb.settings.js should be evaluated as a function but doesn't end in ')'",
"App folderlaunch file folderlaunch.settings.js should be evaluated as a function but doesn't end in ')'",
"App gassist file gassist.settings.js should be evaluated as a function but doesn't end in ')'",
"App gbmusic file gbmusic.settings.js should be evaluated as a function but doesn't end in ')'",
"App getup file getup.settings.js should be evaluated as a function but doesn't end in ')'",
"App gipy file gipy.settings.js should be evaluated as a function but doesn't end in ')'",
"App gpsrec file gpsrec.settings.js should be evaluated as a function but doesn't end in ')'",
"App gpssetup file gpssetup.settings.js should be evaluated as a function but doesn't end in ')'",
"App iconlaunch file iconlaunch.settings.js should be evaluated as a function but doesn't end in ')'",
"App infoclk file infoclk.settings.js should be evaluated as a function but doesn't end in ')'",
"App largeclock file largeclock.settings.js should be evaluated as a function but doesn't end in ')'",
"App launch file launch.settings.js should be evaluated as a function but doesn't end in ')'",
"App messagelist file messagelist.settings.js should be evaluated as a function but doesn't end in ')'",
"App messages file messages.settings.js should be evaluated as a function but doesn't end in ')'",
"App messages_light file messages_light.settings.js should be evaluated as a function but doesn't end in ')'",
"App messagesoverlay file messagesoverlay.settings.js should be evaluated as a function but doesn't end in ')'",
"App metronome file metronome.settings.js should be evaluated as a function but doesn't end in ')'",
"App multitimer file multitimer.settings.js should be evaluated as a function but doesn't end in ')'",
"App nesclock file nesclock.settings.js should be evaluated as a function but doesn't end in ')'",
"App nightwatch file nightwatch.settings.js should be evaluated as a function but doesn't end in ')'",
"App owmweather file owmweather.settings.js should be evaluated as a function but doesn't end in ')'",
"App pebble file pebble.settings.js should be evaluated as a function but doesn't end in ')'",
"App pebbled file pebbled.settings.js should be evaluated as a function but doesn't end in ')'",
"App pongclock file pongclock.settings.js should be evaluated as a function but doesn't end in ')'",
"App popconlaunch file popcon.settings.js should be evaluated as a function but doesn't end in ')'",
"App poweroff file poweroff.settings.js should be evaluated as a function but doesn't end in ')'",
"App puzzle15 file puzzle15.settings.js should be evaluated as a function but doesn't end in ')'",
"App qcenter file qcenter.settings.js should be evaluated as a function but doesn't end in ')'",
"App rebbleagenda file rebbleagenda.settings.js should be evaluated as a function but doesn't end in ')'",
"App recorder file recorder.clkinfo.js should be evaluated as a function but doesn't end in ')'",
"App rep file rep.settings.js should be evaluated as a function but doesn't end in ')'",
"App saclock file saclock.settings.js should be evaluated as a function but doesn't end in ')'",
"App sched file sched.settings.js should be evaluated as a function but doesn't end in ')'",
"App score file score.settings.js should be evaluated as a function but doesn't end in ')'",
"App sensortools file sensortools.settings.js should be evaluated as a function but doesn't end in ')'",
"App shadowclk file shadowclk.settings.js should be evaluated as a function but doesn't end in ')'",
"App shortcuts file shortcuts.settings.js should be evaluated as a function but doesn't end in ')'",
"App simplebgclock file simplebgclock.settings.js should be evaluated as a function but doesn't end in ')'",
"App slomoclock file slomoclock.settings.js should be evaluated as a function but doesn't end in ')'",
"App slopeclockpp file slopeclockpp.settings.js should be evaluated as a function but doesn't end in ')'",
"App smclock file smclock.settings.js should be evaluated as a function but doesn't end in ')'",
"App speedalt file speedalt.settings.js should be evaluated as a function but doesn't end in ')'",
"App speedalt2 file speedalt2.settings.js should be evaluated as a function but doesn't end in ')'",
"App swp2clk file swp2clk.settings.js should be evaluated as a function but doesn't end in ')'",
"App taglaunch file taglaunch.settings.js should be evaluated as a function but doesn't end in ')'",
"App thunder file thunder.settings.js should be evaluated as a function but doesn't end in ')'",
"App timecal file timecal.settings.js should be evaluated as a function but doesn't end in ')'",
"App timerclk file timerclk.settings.js should be evaluated as a function but doesn't end in ')'",
"App timestamplog file timestamplog.settings.js should be evaluated as a function but doesn't end in ')'",
"App toucher file toucher.settings.js should be evaluated as a function but doesn't end in ')'",
"App touchtimer file touchtimer.settings.js should be evaluated as a function but doesn't end in ')'",
"App trex file trex.settings.js should be evaluated as a function but doesn't end in ')'",
"App usgs file usgs.settings.js should be evaluated as a function but doesn't end in ')'",
"App weatherClock file weatherClock.settings.js should be evaluated as a function but doesn't end in ')'",
"App wid_edit file wid_edit.settings.js should be evaluated as a function but doesn't end in ')'",
"App widalarmeta file widalarmeta.settings.js should be evaluated as a function but doesn't end in ')'",
"App widbaroalarm file widbaroalarm.settings.js should be evaluated as a function but doesn't end in ')'",
"App widbatwarn file widbatwarn.settings.js should be evaluated as a function but doesn't end in ')'",
"App widbgjs file widbgjs.settings.js should be evaluated as a function but doesn't end in ')'",
"App widdst file widdst.settings.js should be evaluated as a function but doesn't end in ')'",
"App widgps file widgps.settings.js should be evaluated as a function but doesn't end in ')'",
"App widhrm file widhrm.settings.js should be evaluated as a function but doesn't end in ')'",
"App widmp file widmp.settings.js should be evaluated as a function but doesn't end in ')'",
"App widsleepstatus file widsleepstatus.settings.js should be evaluated as a function but doesn't end in ')'",
];
var apps = [];