diff --git a/README.md b/README.md index 985d5ac5a..0a92aae30 100644 --- a/README.md +++ b/README.md @@ -514,7 +514,6 @@ The [`testing`](testing) folder contains snippets of code that might be useful f * `testing/colors.js` - 16 bit colors as name value pairs * `testing/gpstrack.js` - code to store a GPS track in Bangle.js storage and output it back to the console -* `testing/map` - code for splitting an image into map tiles and then displaying them ## Credits diff --git a/apps/acmaze/ChangeLog b/apps/acmaze/ChangeLog index 88e918a27..b8c1ec0b5 100644 --- a/apps/acmaze/ChangeLog +++ b/apps/acmaze/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Faster maze generation +0.03: Avoid clearing bottom widgets diff --git a/apps/acmaze/app.js b/apps/acmaze/app.js index 3f8a6d820..16a1ce561 100644 --- a/apps/acmaze/app.js +++ b/apps/acmaze/app.js @@ -11,13 +11,10 @@ function Maze(n) { this.margin = Math.floor((g.getHeight()-this.total_length)/2); this.ball_x = 0; this.ball_y = 0; - this.clearScreen = function() { - g.clearRect( - 0, this.margin, - g.getWidth(), this.margin+this.total_length - ); - }; - this.clearScreen(); + // This voodoo is needed because otherwise + // bottom line widgets (like digital clock) + // disappear during maze generation + Bangle.drawWidgets(); g.setColor(g.theme.fg); for (let i=0; i<=n; i++) { g.drawRect( @@ -66,7 +63,7 @@ function Maze(n) { if (Math.random()<0.5 && candidates_down.length || !candidates_right.length) { trying_down = true; } - let candidates = trying_down ? candidates_down : candidates_right; + let candidates = trying_down ? candidates_down : candidates_right, candidate_index = Math.floor(Math.random()*candidates.length), cell = candidates.splice(candidate_index, 1)[0], r = Math.floor(cell/n), @@ -105,11 +102,6 @@ function Maze(n) { } } } - this.clearScreen = function() { - g.clearRect( - 0, MARGIN, g.getWidth(), g.getHeight()-MARGIN-1 - ); - }; this.clearCell = function(r, c) { if (!r && !c) { g.setColor("#ffff00"); @@ -263,7 +255,7 @@ let mazeMenu = { "< Exit": function() { setTimeout(load, 100); } // timeout voodoo prevents deadlock }; -g.clear(true); +g.reset(); Bangle.loadWidgets(); Bangle.drawWidgets(); Bangle.setLocked(false); @@ -289,7 +281,7 @@ let maze_interval = setInterval( duration = Date.now()-start_time; g.setFontAlign(0,0).setColor(g.theme.fg); g.setFont("Vector",18); - g.drawString(`Solved ${maze.n}X${maze.n} in\n ${timeToText(duration)} \nClick to play again`, g.getWidth()/2, g.getHeight()/2, true); + g.drawString(`Solved ${maze.n}X${maze.n} in\n ${timeToText(duration)} \nBtn1 to play again`, g.getWidth()/2, g.getHeight()/2, true); } } }, 25); diff --git a/apps/acmaze/metadata.json b/apps/acmaze/metadata.json index f453d8d85..d8ab8fa62 100644 --- a/apps/acmaze/metadata.json +++ b/apps/acmaze/metadata.json @@ -1,7 +1,7 @@ { "id": "acmaze", "name": "AccelaMaze", "shortName":"AccelaMaze", - "version":"0.02", + "version":"0.03", "description": "Tilt the watch to roll a ball through a maze.", "icon": "app.png", "tags": "game", diff --git a/apps/bthrm/ChangeLog b/apps/bthrm/ChangeLog index 481d855c8..c035dde79 100644 --- a/apps/bthrm/ChangeLog +++ b/apps/bthrm/ChangeLog @@ -5,3 +5,5 @@ 0.03: Prevent readings from internal sensor mixing into BT values Mark events with src property Show actual source of event in app +0.04: Automatically reconnect BT sensor + App buzzes if no BTHRM events for more than 3 seconds diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js index fbc872630..e651515d5 100644 --- a/apps/bthrm/boot.js +++ b/apps/bthrm/boot.js @@ -1,13 +1,28 @@ (function() { - var log = function() {};//print + //var sf = require("Storage").open("bthrm.log","a"); + var log = function(text, param){ + /*var logline = Date.now().toFixed(3) + " - " + text; + if (param){ + logline += " " + JSON.stringify(param); + } + sf.write(logline + "\n"); + print(logline);*/ + } + + log("Start"); + + var blockInit = false; var gatt; - var status; + var currentRetryTimeout; + var initialRetryTime = 40; + var maxRetryTime = 60000; + var retryTime = initialRetryTime; var origIsHRMOn = Bangle.isHRMOn; Bangle.isBTHRMOn = function(){ - return (status=="searching" || status=="connecting") || (gatt!==undefined); - } + return (gatt!==undefined && gatt.connected); + }; Bangle.isHRMOn = function() { var settings = require('Storage').readJSON("bthrm.json", true) || {}; @@ -18,16 +33,135 @@ return Bangle.isBTHRMOn(); } return origIsHRMOn() || Bangle.isBTHRMOn(); + }; + + var serviceFilters = [{ + services: [ + "180d" + ] + }]; + + function retry(){ + log("Retry with time " + retryTime); + if (currentRetryTimeout){ + log("Clearing timeout " + currentRetryTimeout); + clearTimeout(currentRetryTimeout); + currentRetryTimeout = undefined; + } + + var clampedTime = retryTime < 200 ? 200 : initialRetryTime; + currentRetryTimeout = setTimeout(() => { + log("Set timeout for retry as " + clampedTime); + initBt(); + }, clampedTime); + + retryTime = Math.pow(retryTime, 1.1); + if (retryTime > maxRetryTime){ + retryTime = maxRetryTime; + } + } + + function onDisconnect(reason) { + log("Disconnect: " + reason); + log("Gatt: ", gatt); + retry(); + } + + function onCharacteristic(event) { + var settings = require('Storage').readJSON("bthrm.json", true) || {}; + var dv = event.target.value; + var flags = dv.getUint8(0); + // 0 = 8 or 16 bit + // 1,2 = sensor contact + // 3 = energy expended shown + // 4 = RR interval + var bpm = (flags & 1) ? (dv.getUint16(1) / 100 /* ? */ ) : dv.getUint8(1); // 8 or 16 bit + /* var idx = 2 + (flags&1); // index of next field + if (flags&8) idx += 2; // energy expended + if (flags&16) { + var interval = dv.getUint16(idx,1); // in milliseconds + }*/ + + Bangle.emit(settings.replace ? "HRM" : "BTHRM", { + bpm: bpm, + confidence: bpm == 0 ? 0 : 100, + src: settings.replace ? "bthrm" : undefined + }); } - Bangle.setBTHRMPower = function(isOn, app) { - + var reUseCounter=0; + function initBt() { + log("initBt with blockInit: " + blockInit); + if (blockInit){ + retry(); + return; + } + + blockInit = true; + + var connectionPromise; + + if (reUseCounter > 3){ + log("Reuse counter to high") + if (gatt.connected == true){ + try { + log("Force disconnect with gatt: ", gatt); + gatt.disconnect(); + } catch(e) { + log("Error during force disconnect", e); + } + } + gatt=undefined; + reUseCounter = 0; + } + + if (!gatt){ + var requestPromise = NRF.requestDevice({ filters: serviceFilters }); + connectionPromise = requestPromise.then(function(device) { + gatt = device.gatt; + log("Gatt after request:", gatt); + gatt.device.on('gattserverdisconnected', onDisconnect); + }); + } else { + reUseCounter++; + log("Reusing gatt:", gatt); + connectionPromise = gatt.connect(); + } + + + var servicePromise = connectionPromise.then(function() { + return gatt.getPrimaryService(0x180d); + }); + + var characteristicPromise = servicePromise.then(function(service) { + log("Got service:", service); + return service.getCharacteristic(0x2A37); + }); + + var notificationPromise = characteristicPromise.then(function(c) { + log("Got characteristic:", c); + c.on('characteristicvaluechanged', onCharacteristic); + return c.startNotifications(); + }); + notificationPromise.then(()=>{ + log("Wait for notifications"); + retryTime = initialRetryTime; + blockInit=false; + }); + notificationPromise.catch((e) => { + log("Error:", e); + blockInit = false; + retry(); + }); + } + + + Bangle.setBTHRMPower = function(isOn, app) { var settings = require('Storage').readJSON("bthrm.json", true) || {}; // Do app power handling if (!app) app="?"; - log("setBTHRMPower ->", isOn, app); if (Bangle._PWR===undefined) Bangle._PWR={}; if (Bangle._PWR.BTHRM===undefined) Bangle._PWR.BTHRM=[]; if (isOn && !Bangle._PWR.BTHRM.includes(app)) Bangle._PWR.BTHRM.push(app); @@ -35,63 +169,19 @@ isOn = Bangle._PWR.BTHRM.length; // so now we know if we're really on if (isOn) { - log("setBTHRMPower on", app); if (!Bangle.isBTHRMOn()) { - log("BTHRM not already on"); - status = "searching"; - NRF.requestDevice({ filters: [{ services: ['180D'] }] }).then(function(device) { - log("Found device "+device.id); - status = "connecting"; - device.on('gattserverdisconnected', function(reason) { - gatt = undefined; - }); - return device.gatt.connect(); - }).then(function(g) { - log("Connected"); - gatt = g; - return gatt.getPrimaryService(0x180D); - }).then(function(service) { - return service.getCharacteristic(0x2A37); - }).then(function(characteristic) { - log("Got characteristic"); - characteristic.on('characteristicvaluechanged', function(event) { - var dv = event.target.value; - var flags = dv.getUint8(0); - // 0 = 8 or 16 bit - // 1,2 = sensor contact - // 3 = energy expended shown - // 4 = RR interval - var bpm = (flags&1) ? (dv.getUint16(1)/100/* ? */) : dv.getUint8(1); // 8 or 16 bit - /* var idx = 2 + (flags&1); // index of next field - if (flags&8) idx += 2; // energy expended - if (flags&16) { - var interval = dv.getUint16(idx,1); // in milliseconds - }*/ - - Bangle.emit(settings.replace?"HRM":"BTHRM", { - bpm:bpm, - confidence:100, - src:settings.replace?"bthrm":undefined - }); - }); - return characteristic.startNotifications(); - }).then(function() { - log("Ready"); - status = "ok"; - }).catch(function(err) { - log("Error",err); - gatt = undefined; - status = "error"; - }); + initBt(); } } else { // not on - log("setBTHRMPower off", app); + log("Power off for " + app); if (gatt) { - log("BTHRM connected - disconnecting"); - status = undefined; - try {gatt.disconnect();}catch(e) { - log("BTHRM disconnect error", e); + try { + log("Disconnect with gatt: ", gatt); + gatt.disconnect(); + } catch(e) { + log("Error during disconnect", e); } + blockInit = false; gatt = undefined; } } @@ -100,24 +190,29 @@ var origSetHRMPower = Bangle.setHRMPower; Bangle.setHRMPower = function(isOn, app) { + log("setHRMPower for " + app + ":" + (isOn?"on":"off")); var settings = require('Storage').readJSON("bthrm.json", true) || {}; if (settings.enabled || !isOn){ + log("Enable BTHRM power"); Bangle.setBTHRMPower(isOn, app); } if ((settings.enabled && !settings.replace) || !settings.enabled || !isOn){ + log("Enable HRM power"); origSetHRMPower(isOn, app); } } var settings = require('Storage').readJSON("bthrm.json", true) || {}; if (settings.enabled && settings.replace){ - if (!(Bangle._PWR===undefined) && !(Bangle._PWR.HRM===undefined)){ - for (var i = 0; i < Bangle._PWR.HRM.length; i++){ - var app = Bangle._PWR.HRM[i]; - origSetHRMPower(0, app); - Bangle.setBTHRMPower(1, app); - if (Bangle._PWR.HRM===undefined) break; + log("Replace HRM event"); + if (!(Bangle._PWR===undefined) && !(Bangle._PWR.HRM===undefined)){ + for (var i = 0; i < Bangle._PWR.HRM.length; i++){ + var app = Bangle._PWR.HRM[i]; + log("Moving app " + app); + origSetHRMPower(0, app); + Bangle.setBTHRMPower(1, app); + if (Bangle._PWR.HRM===undefined) break; + } } } -} })(); diff --git a/apps/bthrm/bthrm.js b/apps/bthrm/bthrm.js index 712344b11..de769d085 100644 --- a/apps/bthrm/bthrm.js +++ b/apps/bthrm/bthrm.js @@ -10,7 +10,9 @@ function draw(y, event, type, counter) { g.reset(); g.setFontAlign(0,0); g.clearRect(0,y,g.getWidth(),y+75); - if (type == null || event == null || counter == 0) return; + if (type == null || event == null || counter == 0){ + return; + } var str = event.bpm + ""; g.setFontVector(40).drawString(str,px,y+20); str = "Confidence: " + event.confidence; @@ -21,21 +23,27 @@ function draw(y, event, type, counter) { } function onBtHrm(e) { - print("Event for BT " + JSON.stringify(e)); - counterBt += 5; + //print("Event for BT " + JSON.stringify(e)); + if (e.bpm == 0){ + Bangle.buzz(100,0.2); + } + if (counterBt == 0){ + Bangle.buzz(200,0.5); + } + counterBt += 3; eventBt = e; } function onHrm(e) { - print("Event for Int " + JSON.stringify(e)); - counterInt += 5; + //print("Event for Int " + JSON.stringify(e)); + counterInt += 3; eventInt = e; } Bangle.on('BTHRM', onBtHrm); Bangle.on('HRM', onHrm); -Bangle.setHRMPower(1,'bthrm') +Bangle.setHRMPower(1,'bthrm'); g.clear(); Bangle.loadWidgets(); @@ -47,13 +55,13 @@ g.drawString("Please wait...",g.getWidth()/2,g.getHeight()/2 - 16); function drawInt(){ counterInt--; if (counterInt < 0) counterInt = 0; - if (counterInt > 5) counterInt = 5; + if (counterInt > 3) counterInt = 3; draw(24, eventInt, "HRM", counterInt); } function drawBt(){ counterBt--; if (counterBt < 0) counterBt = 0; - if (counterBt > 5) counterBt = 5; + if (counterBt > 3) counterBt = 3; draw(100, eventBt, "BTHRM", counterBt); } diff --git a/apps/bthrm/metadata.json b/apps/bthrm/metadata.json index db2c65d26..68734aafe 100644 --- a/apps/bthrm/metadata.json +++ b/apps/bthrm/metadata.json @@ -2,7 +2,7 @@ "id": "bthrm", "name": "Bluetooth Heart Rate Monitor", "shortName": "BT HRM", - "version": "0.03", + "version": "0.04", "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.", "icon": "app.png", "type": "app", diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index 8c7192c46..4a23c944f 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -12,3 +12,4 @@ Support to show time and progress until next sunrise or sunset Load daily steps from Bangle health if available 0.07: Allow configuration of minimal heart rate confidence +0.08: Allow configuration of up to 4 circles in a row diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 628979555..242adcf4b 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -1,6 +1,6 @@ # Circles clock -A clock with circles for different data at the bottom in a probably familiar style +A clock with three or four circles for different data at the bottom in a probably familiar style By default the time, date and day of week is shown. @@ -18,6 +18,8 @@ It can show the following information (this can be configured): ## Screenshots ![Screenshot dark theme](screenshot-dark.png) ![Screenshot light theme](screenshot-light.png) +![Screenshot dark theme with four circles](screenshot-dark-4.png) +![Screenshot light theme with four circles](screenshot-light-4.png) ## Creator Marco ([myxor](https://github.com/myxor)) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 54c1b2b44..5b7569d63 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -23,31 +23,27 @@ const weatherStormy = heatshrink.decompress(atob("iEQwYLIg/gAgUB///wAFBh/AgfwgED const sunSetDown = heatshrink.decompress(atob("iEQwIHEgOAAocT5EGtEEkF//wLDg1ggfACoo")); const sunSetUp = heatshrink.decompress(atob("iEQwIHEgOAAocT5EGtEEkF//wRFgfAg1gBIY")); -let settings; - -function loadSettings() { - settings = storage.readJSON("circlesclock.json", 1) || { - 'minHR': 40, - 'maxHR': 200, - 'confidence': 0, - 'stepGoal': 10000, - 'stepDistanceGoal': 8000, - 'stepLength': 0.8, - 'batteryWarn': 30, - 'showWidgets': false, - 'weatherCircleData': 'humidity', - 'circle1': 'hr', - 'circle2': 'steps', - 'circle3': 'battery' - }; - // Load step goal from pedometer widget as fallback - if (settings.stepGoal == undefined) { - const d = require('Storage').readJSON("wpedom.json", 1) || {}; - settings.stepGoal = d != undefined && d.settings != undefined ? d.settings.goal : 10000; - } +let settings = storage.readJSON("circlesclock.json", 1) || { + 'minHR': 40, + 'maxHR': 200, + 'confidence': 0, + 'stepGoal': 10000, + 'stepDistanceGoal': 8000, + 'stepLength': 0.8, + 'batteryWarn': 30, + 'showWidgets': false, + 'weatherCircleData': 'humidity', + 'circleCount': 3, + 'circle1': 'hr', + 'circle2': 'steps', + 'circle3': 'battery', + 'circle4': 'weather' +}; +// Load step goal from pedometer widget as fallback +if (settings.stepGoal == undefined) { + const d = require('Storage').readJSON("wpedom.json", 1) || {}; + settings.stepGoal = d != undefined && d.settings != undefined ? d.settings.goal : 10000; } -loadSettings(); - /* * Read location from myLocation app @@ -58,6 +54,7 @@ function getLocation() { let location = getLocation(); const showWidgets = settings.showWidgets || false; +const circleCount = settings.circleCount || 3; let hrtValue; let now = Math.round(new Date().getTime() / 1000); @@ -78,11 +75,33 @@ const hOffset = 30 - widgetOffset; const h1 = Math.round(1 * h / 5 - hOffset); const h2 = Math.round(3 * h / 5 - hOffset); const h3 = Math.round(8 * h / 8 - hOffset - 3); // circle y position -const circlePosX = [Math.round(w / 6), Math.round(3 * w / 6), Math.round(5 * w / 6)]; // cirle x positions -const radiusOuter = 25; -const radiusInner = 20; -const circleFont = "Vector:15"; -const circleFontBig = "Vector:16"; + +/* + * circle x positions + * depending on circleCount + * + * | 1 2 3 4 5 6 | + * | (1) (2) (3) | + * => circles start at 1,3,5 / 6 + * + * | 1 2 3 4 5 6 7 8 | + * | (1) (2) (3) (4) | + * => circles start at 1,3,5,7 / 8 + */ +const parts = circleCount * 2; +const circlePosX = [ + Math.round(1 * w / parts), // circle1 + Math.round(3 * w / parts), // circle2 + Math.round(5 * w / parts), // circle3 + Math.round(7 * w / parts), // circle4 +]; + +const radiusOuter = circleCount == 3 ? 25 : 20; +const radiusInner = circleCount == 3 ? 20 : 15; +const circleFont = circleCount == 3 ? "Vector:15" : "Vector:12"; +const circleFontBig = circleCount == 3 ? "Vector:16" : "Vector:13"; +const defaultCircleTypes = ["steps", "hr", "battery", "weather"]; + function draw() { g.clear(true); @@ -122,10 +141,9 @@ function draw() { drawCircle(1); drawCircle(2); drawCircle(3); + if (circleCount >= 4) drawCircle(4); } -const defaultCircleTypes = ["steps", "hr", "battery"]; - function drawCircle(index) { let type = settings['circle' + index]; if (!type) type = defaultCircleTypes[index - 1]; @@ -147,6 +165,7 @@ function drawCircle(index) { drawWeather(w); break; case "sunprogress": + case "sunProgress": drawSunProgress(w); break; case "empty": @@ -169,7 +188,7 @@ function getCirclePosition(type) { if (circlePositionsCache[type] >= 0) { return circlePosX[circlePositionsCache[type]]; } - for (let i = 1; i <= 3; i++) { + for (let i = 1; i <= circleCount; i++) { const setting = settings['circle' + i]; if (setting == type) { circlePositionsCache[type] = i - 1; @@ -319,6 +338,8 @@ function drawWeather(w) { if (code > 0) { const icon = getWeatherIconByCode(code); if (icon) g.drawImage(icon, w - 6, h3 + radiusOuter - 10); + } else { + g.drawString("?", w, h3 + radiusOuter); } } diff --git a/apps/circlesclock/metadata.json b/apps/circlesclock/metadata.json index 899d6e34d..bd2ce751b 100644 --- a/apps/circlesclock/metadata.json +++ b/apps/circlesclock/metadata.json @@ -1,10 +1,10 @@ { "id": "circlesclock", "name": "Circles clock", "shortName":"Circles clock", - "version":"0.07", - "description": "A clock with circles for different data at the bottom in a probably familiar style", + "version":"0.08", + "description": "A clock with three or four circles for different data at the bottom in a probably familiar style", "icon": "app.png", - "screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}], + "screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}, {"url":"screenshot-dark-4.png"}, {"url":"screenshot-light-4.png"}], "type": "clock", "tags": "clock", "supports" : ["BANGLEJS2"], diff --git a/apps/circlesclock/screenshot-dark-4.png b/apps/circlesclock/screenshot-dark-4.png new file mode 100644 index 000000000..4f1a1b457 Binary files /dev/null and b/apps/circlesclock/screenshot-dark-4.png differ diff --git a/apps/circlesclock/screenshot-dark.png b/apps/circlesclock/screenshot-dark.png index 00c0e3399..4bf8cae9f 100644 Binary files a/apps/circlesclock/screenshot-dark.png and b/apps/circlesclock/screenshot-dark.png differ diff --git a/apps/circlesclock/screenshot-light-4.png b/apps/circlesclock/screenshot-light-4.png new file mode 100644 index 000000000..74d9e2740 Binary files /dev/null and b/apps/circlesclock/screenshot-light-4.png differ diff --git a/apps/circlesclock/screenshot-light.png b/apps/circlesclock/screenshot-light.png index af47b30a4..1a746d5bf 100644 Binary files a/apps/circlesclock/screenshot-light.png and b/apps/circlesclock/screenshot-light.png differ diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index fd1ca52be..1c072fc90 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -96,23 +96,36 @@ format: v => weatherData[v], onchange: x => save('weatherCircleData', weatherData[x]), }, - 'left': { + 'circle count': { + value: "circleCount" in settings ? settings.circleCount : 3, + min: 3, + max : 4, + step: 1, + onchange: x => save('circleCount', x), + }, + 'circle1': { value: settings.circle1 ? valuesCircleTypes.indexOf(settings.circle1) : 0, min: 0, max: 6, format: v => namesCircleTypes[v], onchange: x => save('circle1', valuesCircleTypes[x]), }, - 'middle': { + 'circle2': { value: settings.circle2 ? valuesCircleTypes.indexOf(settings.circle2) : 2, min: 0, max: 6, format: v => namesCircleTypes[v], onchange: x => save('circle2', valuesCircleTypes[x]), }, - 'right': { + 'circle3': { value: settings.circle3 ? valuesCircleTypes.indexOf(settings.circle3) : 3, min: 0, max: 6, format: v => namesCircleTypes[v], onchange: x => save('circle3', valuesCircleTypes[x]), + }, + 'circle4': { + value: settings.circle4 ? valuesCircleTypes.indexOf(settings.circle4) : 4, + min: 0, max: 6, + format: v => namesCircleTypes[v], + onchange: x => save('circle4', valuesCircleTypes[x]), } }); }); diff --git a/apps/diract/ChangeLog b/apps/diract/ChangeLog index 5560f00bc..34fc73a76 100644 --- a/apps/diract/ChangeLog +++ b/apps/diract/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Tweaked proximity identification settings diff --git a/apps/diract/README.md b/apps/diract/README.md index efecade3f..49e6e7add 100644 --- a/apps/diract/README.md +++ b/apps/diract/README.md @@ -5,7 +5,7 @@ ## Usage -Real-time interactions will be recognised by [Pareto Anywhere](https://www.reelyactive.com/pareto/anywhere/) open source middleware and any other program which observes the [DirAct open standard](https://reelyactive.github.io/diract/). +Real-time interactions will be recognised by [Pareto Anywhere](https://www.reelyactive.com/pareto/anywhere/) open source middleware and any other program which observes the [DirAct open standard](https://reelyactive.github.io/diract/). See our [Bangle.js Development Guide](https://reelyactive.github.io/diy/banglejs-dev/) for details. ## Features diff --git a/apps/diract/diract.js b/apps/diract/diract.js index dba41cccb..69f0a88e4 100644 --- a/apps/diract/diract.js +++ b/apps/diract/diract.js @@ -1,5 +1,5 @@ /** - * Copyright reelyActive 2017-2021 + * Copyright reelyActive 2017-2022 * We believe in an open Internet of Things * * DirAct is jointly developed by reelyActive and Code Blue Consulting @@ -11,14 +11,14 @@ const NAMESPACE_FILTER_ID = [ 0xc0, 0xde, 0xb1, 0x0e, 0x1d, 0xd1, 0xe0, 0x1b, 0xed, 0x0c ]; const EXCITER_INSTANCE_IDS = new Uint32Array([ 0xe8c17e45 ]); const RESETTER_INSTANCE_IDS = new Uint32Array([ 0x4e5e77e4 ]); -const PROXIMITY_RSSI_THRESHOLD = -65; -const PROXIMITY_LED_RSSI_THRESHOLD = -65; +const PROXIMITY_RSSI_THRESHOLD = -85; +const PROXIMITY_LED_RSSI_THRESHOLD = -85; const PROXIMITY_TABLE_SIZE = 8; const DIGEST_TABLE_SIZE = 32; const OBSERVE_PERIOD_MILLISECONDS = 400; -const BROADCAST_PERIOD_MILLISECONDS = 3600; +const BROADCAST_PERIOD_MILLISECONDS = 1600; const BROADCAST_DIGEST_PAGE_MILLISECONDS = 400; -const PROXIMITY_PACKET_INTERVAL_MILLISECONDS = 400; +const PROXIMITY_PACKET_INTERVAL_MILLISECONDS = 200; const DIGEST_PACKET_INTERVAL_MILLISECONDS = 100; const DIGEST_TIME_CYCLE_THRESHOLD = 86400; const EXCITER_HOLDOFF_SECONDS = 60; diff --git a/apps/diract/metadata.json b/apps/diract/metadata.json index 0c4780397..af9406e91 100644 --- a/apps/diract/metadata.json +++ b/apps/diract/metadata.json @@ -2,7 +2,7 @@ "id": "diract", "name": "DirAct", "shortName": "DirAct", - "version": "0.01", + "version": "0.02", "description": "Proximity interaction detection.", "icon": "diract.png", "type": "app", diff --git a/apps/fwupdate/ChangeLog b/apps/fwupdate/ChangeLog index 458d695f0..06f84a11a 100644 --- a/apps/fwupdate/ChangeLog +++ b/apps/fwupdate/ChangeLog @@ -4,3 +4,4 @@ Take 'beta' tag off 0.03: Improve bootloader update safety. Now sets unsafeFlash:1 to allow flash with 2v11 and later Add CRC checks for common bootloaders that we know don't work +0.04: Include a precompiled bootloader for easy bootloader updates diff --git a/apps/fwupdate/bootloader_espruino_2v11.52_banglejs2.hex b/apps/fwupdate/bootloader_espruino_2v11.52_banglejs2.hex new file mode 100644 index 000000000..6ffe61bff --- /dev/null +++ b/apps/fwupdate/bootloader_espruino_2v11.52_banglejs2.hex @@ -0,0 +1,1715 @@ +:02000002F0000C +:10700000F0FF032039730F0061730F0063730F00EB +:1070100065730F0067730F0069730F0000000000B5 +:1070200000000000000000000000000051A70F0059 +:107030006D730F00000000006F730F0071730F007D +:1070400073730F0073730F0073730F0073730F006C +:1070500073730F0073730F0073730F0073730F005C +:1070600073730F0073730F0073730F0073730F004C +:1070700073730F0073730F0073730F0073730F003C +:1070800029CB0F00A1970F0073730F0073730F00CC +:1070900073730F0073730F0085A30F0073730F00DA +:1070A00073730F0073730F0073730F0073730F000C +:1070B00073730F0073730F000000000000000000E6 +:1070C00073730F0073730F0073730F0073730F00EC +:1070D00073730F0073730F0073730F0073730F00DC +:1070E00073730F0073730F0073730F0000000000C1 +:1070F0000000000073730F000000000073730F00A6 +:10710000000000000000000000000000000000007F +:10711000000000000000000000000000000000006F +:10712000000000000000000000000000000000005F +:10713000000000000000000000000000000000004F +:10714000000000000000000000000000000000003F +:10715000000000000000000000000000000000002F +:10716000000000000000000000000000000000001F +:10717000000000000000000000000000000000000F +:1071800000000000000000000000000000000000FF +:1071900000000000000000000000000000000000EF +:1071A00000000000000000000000000000000000DF +:1071B00000000000000000000000000000000000CF +:1071C00000000000000000000000000000000000BF +:1071D00000000000000000000000000000000000AF +:1071E000000000000000000000000000000000009F +:1071F000000000000000000000000000000000008F +:1072000010B5054C237833B9044B13B10448AFF3E0 +:1072100000800123237010BDC05B0020000000002F +:10722000F8D50F0008B5034B1BB103490348AFF372 +:10723000008008BD00000000C45B0020F8D50F00EE +:10724000154B002B08BF134B9D46A3F5803A002138 +:107250008B460F461348144A121A00F063F80F4B7E +:10726000002B00D098470E4B002B00D098470020F1 +:10727000002104000D000D48002802D00C48AFF397 +:10728000008000F02BF82000290000F0FBFB00F04C +:1072900011F800BF00000800F0FF0320000000000C +:1072A00000000000C05B0020407E002000000000C5 +:1072B0000000000008B5074B044613B10021AFF3EE +:1072C0000080054B1868836A03B19847204600F098 +:1072D00031F800BF000000000CCF0F0070B50D4D5D +:1072E0000D4C641BA4100026A64209D10B4D0C4C7A +:1072F00005F000FE641BA4100026A64205D170BD57 +:1073000055F8043B98470136EEE755F8043B98479B +:107310000136F2E7A45B0020A45B0020A45B002000 +:10732000A85B002002440346934200D1704703F853 +:10733000011BF9E7FEE700BF0649074A074B9B1A06 +:1073400003DD043BC858D050FBDC02F0D9FDFFF749 +:1073500077FF00005CD60F00B8570020C05B00200C +:10736000FEE7FEE7FEE7FEE7FEE7FEE7FEE7FEE7F5 +:10737000FEE7FEE7012359B91F2886BF00F01F0072 +:10738000094A4FF0A04203FA00F0C2F80C0570471A +:107390001F2886BF00F01F00034A4FF0A04203FAE7 +:1073A00000F0C2F8080570470003005010B504460D +:1073B000FFF7E0FF1F2C86BF04F01F04044B4FF0C3 +:1073C000A04304F5E074032243F8242010BD00BF5D +:1073D000000300500B234B4310B503EBE003094CB3 +:1073E00000F0070201209040E25C1043E054064B9D +:1073F0001A688A42C8BF1960044B1A688A42B8BF2B +:10740000196010BDDD5B0020A85F0020205800201F +:1074100070B50F4A0F4C07234FF080614FF00065A5 +:10742000216000BF00BF00BF00BF40FA03F6F607AF +:107430004CBF1560256000BF00BF00BF00BF1160DA +:1074400000BF00BF00BF00BF13F1FF33E8D270BD23 +:10745000080500500C0500502DE9F74F394E3A4D04 +:1074600032682B689A423FDC384CE77B94F810A0D6 +:1074700017F010030CBF0121002150460093FFF7C5 +:1074800079FF37682A68974231DD0020FFF7C0FF97 +:107490000020FFF7BDFF94F8511094F85200C1F39B +:1074A0000011FFF767FF94F84E1094F84F0011F0A9 +:1074B000100118BF0121FFF779FF009B191C18BFAD +:1074C00001215046FFF756FF214BA17C1A78E07C42 +:1074D000C1F30011514081F001011970FFF74AFF1B +:1074E000B023336000232B6003B0BDE8F08F194B4D +:1074F0004FF00B094FEA470B4FF0010809FB073922 +:107500009020FFF785FF0BEB0800FFF781FF0022BB +:10751000D11002F0070019F801100192014111F099 +:10752000010F0CBFFF200020FFF772FF019A01320C +:10753000582AEDD1B8F1020F01D10137A2E74FF07F +:107540000208DDE7A85F00202058002077D10F0057 +:10755000DC5B0020DD5B002010B5094C217E607EE5 +:1075600011F0100118BF0121FFF720FF617DA07D00 +:1075700011F0100118BF0121BDE81040FFF716BF40 +:1075800077D10F002E2A2DE9F84F04460D4634D04E +:107590002B2A34D0602A01D9203AD2B2303A5E2A5E +:1075A00029D8052392FBF3F303EB8303D31AD21AF2 +:1075B00003EB4308134B002603EB420904F1010AD5 +:1075C00004F1020B39F8027B47FA08F7790703D573 +:1075D000A9192046FFF7FEFEBA0703D5A9195046A0 +:1075E000FFF7F8FEFB0703D571195846FFF7F2FEC7 +:1075F0000136052EE6D1BDE8F88F5C22CEE74022A9 +:10760000CCE700BF50CF0F002DE9F041194C1A4DC7 +:10761000DFF87880471E17F8012F1AB9BDE8F0414E +:10762000FFF71ABF21682868FFF7ACFF3B780A2BE9 +:1076300018D12668B31D532B2360ECDD4FF45C7228 +:1076400041460E4805F048FC582200210C48FFF73F +:1076500069FE0C4B00221A600B4B023E572226603B +:107660001A60D8E70D2B16BF2B68022304332B605A +:10767000D1E700BF1C58002018580020DD5B002017 +:107680004D5F0020A85F002020580020355C0020BE +:107690001FB547F630020023CDE901230DF10604A2 +:1076A000CDF80B301C2220FA02F101F00F01CBB211 +:1076B0000929D4BF30333733043A04F8013B131D92 +:1076C000F1D1002301A88DF80E30FFF79DFF04B023 +:1076D00010BD000008B5FFF797FF0248BDE808405D +:1076E000FFF792BFB6CF0F0008B54FF472720021BA +:1076F0000848FFF717FE084A02231360074A136081 +:10770000074B00221A60074BAF221A60BDE8084001 +:10771000FFF7A2BEDD5B0020185800201C58002097 +:10772000A85F00202058002010B5204CE17B207C71 +:1077300011F0100118BF0121FFF738FE94F84E3008 +:1077400094F84F00DA064CBF00210121FFF72EFE0E +:1077500094F8513094F85200DB064CBF002101210F +:10776000FFF724FE637DA07DD9064CBF00210121D7 +:10777000FFF71CFEA37CE07CDA064CBF0021012150 +:10778000FFF714FE237E607EDB064CBF0021012143 +:10779000FFF70CFE064B074843F001039847FFF73D +:1077A000A3FFBDE81040FFF79FBF00BF77D10F00D8 +:1077B000B0CF0F0000C40900094A92F8343092F8A3 +:1077C00033201F2B8ABF07494FF0A04103F01F034E +:1077D000D1F81005D84080EA121000F0010070477F +:1077E00077D10F000003005008B5FFF7E5FF104AFE +:1077F00060B910600F4B104AC3F8002640F6CD4127 +:1078000000220E48BDE8084001F08ABE136801332B +:107810000A2B1360EEDDBFF34F8F0949094BCA688D +:1078200002F4E0621343CB60BFF34F8F00BFFDE76C +:10783000C45F0020000001403546526EAC5F00205E +:1078400000ED00E00400FA05C1B91F2887BF00F071 +:107850001F01114A01464FF0A04201238B40C2F89C +:107860000C351F2886BF00F01F000B4B4FF0A043C4 +:1078700000F5E070032243F8202070471F2887BFDF +:1078800000F01F01044A01464FF0A04201238B4043 +:10789000C2F80835E5E700BF0003005070477047A5 +:1078A000274E80B5FFF758FE00F0C6FB96F839303A +:1078B00096F83A4013F0100514BF0021012120462C +:1078C0002746FFF7C1FFFFF777FF0028FBD1012311 +:1078D00055BB1F2C86BF04F01F071A4A4FF0A04269 +:1078E000BB40C2F80C3596F834201F2A86BF154BD2 +:1078F00002F01F024FF0A04303EB8203124AC3F8C9 +:107900000027D3F8002722F44032C3F80027D3F829 +:10791000002742F44032C3F800274FF08043012291 +:10792000DA67C3F80025FEE71F2C86BF04F01F07A7 +:10793000044A4FF0A042BB40C2F80835D3E700BF6D +:1079400077D10F00000300500C00030070B5FFF763 +:1079500033FF234B1B6A0446DBB92248FFF7BAFE0C +:10796000002C3AD02048214D214EFFF74DFE4FF418 +:10797000206445F00105FFF71FFF38B35CB14FF6F7 +:10798000C010A847630602D13046FFF73DFE013C18 +:10799000F1E70028E6D11748FFF79CFE134B164885 +:1079A00043F001039847154B01214FF42032C3F8EF +:1079B0000C15C3F80425D3F808250A43C3F8082595 +:1079C0000F4A19600020C3F8002670BD002CE2D0D9 +:1079D000FFF78AFE0B48FFF77DFE0120F5E700BFA9 +:1079E00098730020E6CF0F00F4CF0F00E0CF0F0018 +:1079F00031D00F003DD00F0000A861000000014011 +:107A00003546526E33D00F0008B5084A08480121A8 +:107A100001F07AFD002240F6CD41064801F080FDDC +:107A20000548BDE80840FFF755BE00BFE9770F00E5 +:107A300074D00F00AC5F002055D00F000148FFF755 +:107A400049BE00BF4DD00F000148FFF743BE00BF45 +:107A50004AD00F00072810D8DFE800F004090B0D0A +:107A60000F060F06FFF7D0BF0448FFF733BEFFF73E +:107A7000E5BFFFF7E9BF0248F7E7704763D00F00A3 +:107A800069D00F00F8B5334B93F8331093F83420D6 +:107A900011F0100F0CBF012103211F2A86BF02F035 +:107AA0001F022D484FF0A04002F5E072890040F817 +:107AB000221093F8391093F83A0011F0100118BF12 +:107AC0000121FFF7C1FE4FF08043D3F8005415F0B9 +:107AD0000B0F13D115F00F0705D0FFF76DFE68B936 +:107AE00067B9FFF7DDFE1D4E4FF47A7446F00106CC +:107AF0004FF47A40B047013CFAD1EEE7FFF714FEAD +:107B0000174CEB0702D52046FFF7E4FD6D106278B5 +:107B1000631CEAB95B780234002BF2D14FF080434A +:107B20004FF0FF32C3F800240E48FFF7D3FDFFF7F4 +:107B300043FE08B900F006FA084B0B4843F0010376 +:107B400098470A4804F0C4FD04F01AFE0020F8BD6E +:107B50001C46DCE777D10F0000030050E0CF0F0098 +:107B6000B9CF0F0078D00F000048E801557A0F0018 +:107B7000024B800143F00103184700BF90D00F0073 +:107B800007B5AB238DF8073001210DF10700044B39 +:107B900098473220FFF7ECFF03B05DF804FB00BF0D +:107BA0003D5900201F2886BF00F01F00064B4FF0F4 +:107BB000A0430122824000F5E070C3F808250322AB +:107BC00043F82020704700BF000300502DE9F34127 +:107BD0003149324C91F82B00314FFFF7E3FF91F818 +:107BE0002E00FFF7DFFF91F83100FFF7DBFF91F880 +:107BF00028301F2B86BF03F01F032A4A4FF0A042F4 +:107C000003F5E0730C2142F823106420FFF7B0FF66 +:107C10006623012101A88DF80430A0479923012192 +:107C200001A88DF80430A0473220FFF7A1FFFFF72D +:107C3000A7FFFFF7A5FFFFF7A3FFFFF7A1FF0425AD +:107C400040F2E9364FF00608013E13D10A20FFF753 +:107C50008FFF0123022101A8ADF80430A0470A20BC +:107C6000FFF786FF013D11D10F48FFF781FF02B0FA +:107C7000BDE8F081B8478307E8D401A801218DF859 +:107C80000480A0470A20FFF773FFDDE7B84710F034 +:107C90001C0FD5D1E8E700BF77D10F003D59002078 +:107CA0008D59002000030050A086010038B50D4614 +:107CB0000A4B014604462022284698472868431C60 +:107CC00009D020F07F4020342044B0F1C14F8CBF58 +:107CD0000020012038BD0020FCE700BFF95900203A +:107CE0002DE9F04FC5B06C4684E80F004E9D0E465E +:107CF000103507460DF110080EB901202BE0B6F53E +:107D0000807FB14628BF4FF48079184B4A462946F8 +:107D1000404698470024434617F804A013F8011B77 +:107D2000514507EB040B19D01148FFF76DFC58467D +:107D3000FFF7AEFC0F48FFF7CDFC18F80400FFF783 +:107D4000A7FC0D48FFF760FC5046FFF7A1FC09486F +:107D5000FFF7C0FC002045B0BDE8F08F01344C4572 +:107D6000DAD125442744361BC6E700BFF959002065 +:107D70006AD10F00B8CF0F0073D10F002DE9F04387 +:107D8000D1B004AC0146594E054610222046B047FA +:107D900023680133B14646D06368002B43D0544872 +:107DA000FFF798FC2068FFF773FC5248FFF792FC3E +:107DB0006068FFF76DFC5048FFF78CFCA068FFF788 +:107DC00067FC4E48FFF786FCE068FFF761FC4C4813 +:107DD000FFF780FC2368B3F5772F24D04948FFF7DD +:107DE00079FC00236668029305F11008002E1DDC63 +:107DF000A268029B9A4232D04348FFF76BFC43488B +:107E0000FFF768FC0298FFF743FC4148FFF762FC6C +:107E10003F48FFF75FFC00233E4A3F493F48089335 +:107E2000089B934215DD51B0BDE8F083B6F5807F25 +:107E30003746A8BF4FF4807741463A4610A8C84756 +:107E400002AA394610A801F0C7FBB8440290F61BFD +:107E5000CCE7C1F80006089B01330893E0E73048FF +:107E6000304EFFF737FC3048FFF734FC009594E8BC +:107E70000F00FFF735FF07462C48FFF72BFC0623C2 +:107E8000012108A88DF82030B047A5F11C0300227D +:107E90000392039AB2F57A7F21DB02228DF820202B +:107EA0001A0C8DF821205BBA1C22002109A8ADF81C +:107EB0002230FFF737FA20210DEB0100B0471C4EAE +:107EC000B047C307FCD46FB91A48FFF703FC1A4840 +:107ED000FFF700FC009594E80F00184CA047039AA8 +:107EE0000132D5E71648FFF7F5FB9CE7F95900206A +:107EF000CCD00F00D9D00F00DFD00F00E5D00F009D +:107F0000EAD00F00F3D00F00FFD00F000CD10F000C +:107F1000B8CF0F003F4B4C00000001403546526E79 +:107F200019D10F003D59002020D10F002BD10F0097 +:107F30008D5900203AD10F004ED10F00E75A002092 +:107F40005AD10F002DE9F043354889B0FFF7C2FB45 +:107F5000FFF73CFE69460020FFF7A8FE28B931482C +:107F6000FFF7B8FB09B0BDE8F0834CF252354FF093 +:107F700000092D4E2D4F4FE09DF804302E2B2AD1B5 +:107F80009DF80530662B26D19DF80630692B22D14D +:107F90009DF80730722B1ED19DF808306D2B1AD139 +:107FA0009DF80930772B16D19DF80A30612B12D13C +:107FB0009DF80B30722B0ED19DF80C30652B0AD139 +:107FC0009DF80D303BB91A48FFF784FB09F12000FA +:107FD000FFF7D4FEC6E7009C24F07F4423344C44D2 +:107FE00024F00308C845BAD308F12003B3F1C14F08 +:107FF000B5D869464046FFF759FE60B9344004F5EC +:1080000080583C4414F1C14FA9D969464046FFF756 +:108010004DFE0028A3D0C146013DADD105489FE7E4 +:1080200096D00F00A4D00F0000F0FFFF0010809F3B +:10803000BDD00F00AED00F0007B5FFF7C7FDB923C5 +:108040008DF8073001210DF10700044B98470220FD +:10805000FFF78EFD03B05DF804FB00BF3D59002023 +:10806000C3F10803DB0070B50133002403A500BF92 +:108070005B1920C940CAAD1920C0184720C940CAA1 +:10808000754120C020C940CA754120C020C940CADE +:10809000754120C020C940CA754120C020C940CACE +:1080A000754120C020C940CA754120C020C940CABE +:1080B000754120C06441204670BD00BF0000000033 +:1080C000C3F10803DB0070B50133002403A500BF32 +:1080D0005B1920C940CAAD1B20C0184720C940CA3F +:1080E000B54120C020C940CAB54120C020C940CAFE +:1080F000B54120C020C940CAB54120C020C940CAEE +:10810000B54120C020C940CAB54120C020C940CADD +:10811000B54120C06441B4FA84F0400970BD00BF8D +:108120002DE9F041013B00249B0025462646A4464C +:108130005FF0000E03E05FEA0C0EBEEB030EBCEB3B +:108140000E0752F8078051F80E70A7FB0878E41963 +:1081500055EB080556F100061EF1040E9E4501DCA4 +:10816000E645ECDD40F80C402C46354600261CF177 +:10817000040C9C45DCDDBCEB430FDCDD40F80C401F +:10818000BDE8F081002310B51C465AB2914200DCD4 +:1081900010BD40F823400133F7E710B500231A461D +:1081A0005CB2A14203DCB2FA82F0400910BD50F883 +:1081B000234001332243F3E74A11012350F8220000 +:1081C00001F01F0103FA01F108407047013910B5B1 +:1081D00049B2041D0A06CBB204D4013954F8212057 +:1081E000002AF7D001335BB273B103F18042013A48 +:1081F00050F82220002022B9013B00EB431318B2B3 +:1082000010BD52080130F6E71846F9E710B5002313 +:108210005CB2A24200DC10BD51F8234040F823407C +:108220000133F5E710B5013A52B2130601D500202B +:1082300010BD50F8224051F822309C4205D802F17E +:10824000FF32F2D24FF0FF30F2E70120F0E700EB0F +:1082500081010023884200D3704751F8042D43EA7E +:1082600052030B60D307F5E770B59DF910401E4629 +:1082700023460546FFF7F4FE30B92246294630462C +:10828000FFF7D0FF012807D023463246294628466B +:10829000BDE87040FFF714BF70BD70B59DF9104088 +:1082A0001E4623460546FFF70BFF38B123463246EC +:1082B00029462846BDE87040FFF7D2BE70BD2DE9C3 +:1082C000F04FB5B004AC9DF9F8501F4681462B46DF +:1082D0002046FFF725FF24AB29463846CDE9023476 +:1082E000FFF774FFC0EB851004B2002C2646B8BF20 +:1082F00004F11F06634246F3471603F01F0304F020 +:108300001F0814A858BFC3F100083146FFF73AFF11 +:10831000B8F1000F30B22DDD14AB002203EB80006A +:10832000C8F1200C1346AB4219D32FB27B00019346 +:1083300014AB03EB870705F1FF3834AB012603EBE1 +:108340008808002C54DA34AB03EB86062A4656F82C +:10835000C81C4846FFF75AFF35B0BDE8F08F57F804 +:10836000236006FA08F10A4340F8042B013326FA89 +:108370000CF2D8E714AB2A46394603EB8000FFF72E +:1083800045FFD2E70FFA82FE5AF8C83C53F82EB0E8 +:1083900034AB03EB8202013052F8803C0B44BBEB60 +:1083A000030334BF012200229B4518BF11465CF82D +:1083B000C82C42F82E30019B42B29A42E2DB731A7B +:1083C0005E42294614A85E41FFF741FF34AB03EB40 +:1083D0008503294653F8802C58F8803C384643EAF8 +:1083E000C273013C48F8803C24B2FFF730FFA8E795 +:1083F00034AB0020C6F1010C014603EB860A03EB07 +:108400008C0CD8E730B51C4691B0054693F9003086 +:108410006846FFF785FED4F8B0306946284698478D +:1084200011B030BD13460A46FFF7ECBF2DE9F04707 +:1084300093F9006092B004468946104631461546CD +:108440009846FFF7AAFE002840F091804246494630 +:1084500002A8FFF7E7FF434602AA21460AA8FFF752 +:10846000D1FF02A908464246FFF7DCFF43462A46F1 +:1084700049464846FFF7C6FF08F104074246294629 +:108480002846FFF7CFFF3B462A4621462046009666 +:10849000FFF7EAFE3B462A46294628460096FFF7A4 +:1084A000E3FE3B462A46214628460096FFF7F5FEA6 +:1084B00043462A4621462046FFF7A4FF3B46224674 +:1084C000214628460096FFF7CFFE3B4600962A46F7 +:1084D00021462046FFF7C8FE2368DB074AD533460E +:1084E0003A4621462046FFF7BBFD314682462046EC +:1084F000FFF7ADFE06F18043013B54F8230040EA4C +:10850000CA7044F82300424621462846FFF78AFFF6 +:108510003B460AAA294628460096FFF7BEFE3B4680 +:108520000AAA294628460096FFF7B7FE0AA9084678 +:108530003B462A460096FFF7B0FE43460AAA21466C +:108540002046FFF75FFF02AA3B46104621460096F1 +:10855000FFF7A3FE324629462046FFF757FE49465D +:108560002846FFF753FE02A94846FFF74FFE12B018 +:10857000BDE8F08731462046FFF769FEC3E72DE9E5 +:10858000F04115468AB0044688461C22002103A803 +:10859000FEF7C8FE2E1D95F9007003232A464146BA +:1085A00020460293FFF73EFF334602AA21462046AB +:1085B0000097FFF772FE2B46424621462046FFF702 +:1085C00021FF0097334605F1840221462046FFF73C +:1085D0004BFE0AB0BDE8F081F0B591B00E461C220A +:1085E0000021074601A8FEF79DFE01241C22002160 +:1085F00009A80094FEF796FE31466A4611F9045B1D +:1086000008942B466846FFF72BFD29466846FFF77E +:10861000DDFD013804B2012C06DC2A4608A93846E3 +:10862000FFF7F4FD11B0F0BD08A908463246FFF788 +:10863000F9FE21466846FFF7BFFD28B108A9334679 +:108640003A460846FFF7DEFE013C24B2E3E70000AD +:10865000F0B5082289B00C460646FFF7D7FDCB6A75 +:1086600003930B6B04934B6B05938B6B0693CB6B54 +:108670000793002708236A4669466846CDE90177D3 +:108680000097FFF7EDFC082305466A463146304661 +:10869000FFF7E6FC236B0393636B0493A36B0593D3 +:1086A000E36B0544CDE906376A4608236946684608 +:1086B000FFF7D6FC082305446A4631463046FFF7EB +:1086C000CFFC236A0093636A0193A36A0293A36BAE +:1086D0000693E36B0793054408236A463146304608 +:1086E000CDE904770397FFF7BBFC636A0093A36AA5 +:1086F000A26B0193E36A02930492636BE26B0393B0 +:10870000CDE90523236A0793054408236A463146C9 +:108710003046FFF7A5FCE36A0093236B0193636B7C +:108720000293236A0693A36A0793054408236A46C3 +:1087300031463046CDE904770397FFF7C1FC236B40 +:108740000093636B0193A36B0293E36B0393636AE0 +:108750000693E36A07932D1A08236A46314630468A +:10876000CDE90477FFF7ACFC636B0093A36B019337 +:10877000E36B0293236A0393636A0493A36ACDE9CC +:108780000537236B07932D1A08236A463146304676 +:10879000FFF796FCA36B0093E36BCDE90137636AA7 +:1087A0000393A36A0493E36ACDE90537636B0793E8 +:1087B0002D1A08236A4631463046FFF781FC2D1AF0 +:1087C0000D4C0FD435B9082231462046FFF72AFD5B +:1087D00001280FD00823224631463046FFF770FCAF +:1087E0002D1AEFE70823224631463046FFF738FCC2 +:1087F0002D18F7D409B0F0BD0CD20F00F0B5154616 +:1088000089B01C4607460E461A4629466846FFF7B9 +:1088100009FE23466A4639463846FFF7F3FD2346EC +:108820002A4669466846FFF7EDFD23466A4631460B +:108830003046FFF7E7FD09B0F0BD2DE9F0438BB0FE +:108840001446129D15F9046B00961F468046894612 +:108850002B460246214602A8FFF71FFD02A9129AE5 +:108860000846FFF7DFFD129B02AA41464046FFF78C +:10887000C9FD129B02AA21462046FFF7C3FD2B46E5 +:108880004A46394638460096FFF707FD129A3946A0 +:1088900002A8FFF7C7FD02A92B46424608460096EC +:1088A000FFF7FBFC02A92B46224608460096FFF77D +:1088B000F4FC2B464246214620460096FFF7EDFC8D +:1088C000129B224649464846FFF79CFD2B4602AACA +:1088D000414620460096FFF7E0FC129B22463946AF +:1088E0003846FFF78FFD2B464A46394638460096F4 +:1088F000FFF7D3FC324602A92046FFF787FC0BB0F6 +:10890000BDE8F083F8B50E46D11C48BF911D144652 +:1089100041F387010546671EFFF734FC00214AB288 +:10892000A24201F1010100DBF8BDBB1A23F00300F4 +:10893000B25C03F00303DB0002FA03F32A581A4384 +:108940002A50ECE72DE9F0471F46B3F9023089467B +:1089500013F11F0148BF03F13E014D11D91D48BF5E +:1089600003F10E01CC1094424FFA85F828BF14464B +:1089700041460646FFF706FC22464946FFF7C2FF7E +:10898000B7F90220E40094421FD9A41A06EB85012E +:108990000022C4F120058E420ED3243742463146D0 +:1089A0003846FFF73FFC01280FD043463A46304691 +:1089B000BDE8F047FFF784BB51F8040D20FA04F33B +:1089C00013430B6000FA05F2E5E7BDE8F08770B5E8 +:1089D000036813F001050646144605D013460A46FF +:1089E0000146FFF73DFB054621463046FFF72FFCC9 +:1089F00045B104F18042013A56F8223043F0004379 +:108A000046F8223070BDF0B50F46A1B006461946B3 +:108A1000384615461C46FFF7C0FB20B13046FFF72D +:108A2000B1FB21B0F0BD224639466846FFF7EEFBA8 +:108A3000294608A8FFF7EAFB10A82146FFF7A2FB8A +:108A4000012318A81093FFF79DFB224608A968464A +:108A5000FFF7E8FB28B9224610A93046FFF7D6FBFE +:108A6000DFE7009BDA0709D421466846FFF7EFFBF2 +:108A70002246294610A8FFF7AAFFE6E7089BDB0776 +:108A800007D4214608A8FFF7E2FB2246294618A88A +:108A9000F1E7002823461CDD08AA69466846FFF76F +:108AA0000FFB21466846FFF7D2FB224618A910A803 +:108AB000FFF7B8FB002805DA10A923462A46084626 +:108AC000FFF7CEFA10A9234618AA0846FFF7F8FACE +:108AD000CEE708A96A460846FFF7F2FA214608A839 +:108AE000FFF7B5FB224610A918A8FFF79BFB00284B +:108AF00005DA18A923462A460846FFF7B1FA18A94D +:108B0000234610AA0846FFF7DBFABEE70048704785 +:108B100008D20F002DE9F04FFDB01D46869E05924C +:108B2000B6F9023096F9004013F11F0748BF03F170 +:108B30003E0747F3471707F1FF3924AB4FF0000B0F +:108B400043F829B07CAB03EB8902804642F8C0BCF5 +:108B500042F8A0BC8A4696F9012001466CA8FFF7AE +:108B6000D1FEA3000793A2006CAB134496F9012039 +:108B70000493184608EB0201FFF7C4FE294696F954 +:108B800001204CA8FFF7BEFE96F9012054A8A918B1 +:108B9000FFF7B8FE21464CA8FFF7FFFA054600286C +:108BA00040F0348154A8FFF7F8FA8346002840F0DB +:108BB0002B8106F124033A464CA918460393FFF78C +:108BC00031FB012840F022813A4654A90398FFF76F +:108BD00029FB0128069040F019811CAD0DF13008E9 +:108BE0003B46039A54A92846FFF70DFF51464046DD +:108BF0003346059A48F829B0FFF7A4FE414640469F +:108C0000039B00972A46FFF75AFB0DF5B879039BA3 +:108C100000972A464CA914A8FFF751FB2246484664 +:108C20006CA9FFF7F3FAA30009EB030A5046049975 +:108C3000FFF7ECFA06F14403194634A80493FFF752 +:108C4000E5FA049BA10059183CA8FFF7DFFA331D91 +:108C5000494634AA284600940593FFF71EFB534665 +:108C60004A463CA934A80096FFF7E7FD2346321D8B +:108C700029462846FFF7C7FE2A465146484633464E +:108C8000FFF7BCFD049B099339466CAB4046CDE928 +:108C90000A39CDF820B0FFF799FA3946814614A871 +:108CA000FFF794FA8145B8BF81461FFA89F909F1A7 +:108CB000FF331BB2194640460493FFF77DFA049B2D +:108CC00010F10008194614A818BF4FF00108FFF76B +:108CD00073FA002814BF0223002348EA03080DF1A9 +:108CE000200A22465AF8288024A84146FFF78EFA27 +:108CF0000DF1B00AA30008EB03015046FFF786FA16 +:108D000021462846FFF73EFAA9F10208069B2B6090 +:108D10000FFA88F80DF190090495B8F1000F22DAE6 +:108D2000DDE9041223460846FFF76DFE3346049A38 +:108D300051464846FFF762FD3A4649460398FFF719 +:108D400071FA012804D03B46039A4846FFF7B8F968 +:108D5000013C64B24CAA23064DD5BBFA8BF0400906 +:108D60007DB0BDE8F08F049AD6F8A4503346514642 +:108D70004846A84741460CA8FFF71EFA031C18BF37 +:108D80000123414614A80693FFF716FA069B002814 +:108D900014BF02220022134308AA52F823302BB337 +:108DA0002246194634A80693FFF730FADDE906316A +:108DB0003CA85918FFF72AFA3346049A3CA934A86C +:108DC000FFF71CFD059B009434AA494644A8FFF711 +:108DD00064FA53464A463CA934A80096FFF72DFD95 +:108DE0000499334644AA0846FFF70CFB08F1FF3804 +:108DF0000FFA88F891E759F8243052F824104B40C4 +:108E00004BEA030B013CA6E72846A9E75846A7E72B +:108E10002DE9F04FC9B008AA01F1400514464B787E +:108E20000E781B0443EA0663CE7833438E78043110 +:108E300043EA06238D4244F8043BF0D11024916BA1 +:108E400016464FEAF14383EA714383EA9123716A3C +:108E5000366852F8045F31440B444FEAB54181EA69 +:108E6000F51181EAD50101340B44402CD363E6D1DE +:108E7000D0E914E30093836D0193C36D0293036EF5 +:108E80000393436E0493836E0593C36E0693DDE9EB +:108E9000057BDDE9031CDDE901592B4B009E07939F +:108EA00074464FF00008079B53F8042B07934FEAD2 +:108EB000F12383EAB11383EA716A08AB53F82830CF +:108EC0001A440AEB020327EA010A01EA0C028AEAC1 +:108ED00002021A444FEA743A86EA05035A448AEABF +:108EE000B40A06EA050B234083EA0B038AEAB45A64 +:108EF00008F101089A44B8F1400F02EB0903BB46A0 +:108F00005244A94619D172440265009A224442652E +:108F1000019A32448265029A2A44C265039A1A442D +:108F2000049B02660B444366059B63448366069B71 +:108F30003B44C36649B0BDE8F08F674635468C4672 +:108F4000264619461446AEE7BCD20F0030B5E0B154 +:108F50000F4A104900240025C0E91245C0E9141247 +:108F60000D4C0E4A0E4DC0E916420E4AC0E9185289 +:108F70000D4A826602F17452A2F523020023A2F682 +:108F800092420364C266184630BD0E20FCE700BF63 +:108F900085AE67BB67E6096A72F36E3C3AF54FA58A +:108FA0007F520E518C68059BABD9831FF8B50446E0 +:108FB000F0B10AB90020F8BDD1B10D468E180027D6 +:108FC000B542F7D0236C15F8012BE2540133402B46 +:108FD0002364F5D121462046FFF71AFFD4E9123168 +:108FE00013F5007341F10001C4E912312764E7E78A +:108FF0000E20E0E770B50D4616460446002877D0EF +:10900000002975D0026C8021372A02F101038154B6 +:109010004FF0000242D8382B3BD1D4E91223206C08 +:109020000821E1FB0023104612BAE2631A0A19462E +:1090300084F83B3084F83A201A0C1B0EC4E9120164 +:1090400084F83920214684F838302046FFF7E0FEC6 +:10905000691E76B30023E26EDA4001F8012FA26E9A +:10906000DA400A71626EDA400A72226EDA400A73DE +:10907000E26DDA400A74A26DDA400A75626DDA4078 +:109080000A76226DDA400833202B0A77E3D10020DC +:1090900070BDE2540133BEE7E25401333F2BFBD9EC +:1090A00021462046FFF7B4FE38220021FEF73AF9A8 +:1090B000B3E71823226DDA4001F8012F626DDA4020 +:1090C0000A71A26DDA400A72E26DDA400A73226E0A +:1090D000DA400A74626EDA400A75A26EDA400A76E5 +:1090E000E26EDA40083B13F1080F0A77E2D1CEE7CF +:1090F0000E20CDE710B513681F2B144607D90122A7 +:109100000830FFF777FF08B92023236010BD48F22D +:109110001450FBE70830FFF749BF0830FFF716BFD0 +:1091200030B54C1CE40012F00303A4B20ED1084D7C +:109130002A602244074C2260074A1370074A1370C2 +:10914000074A1080074A1846118030BD0720FCE707 +:10915000D05F0020CC5F0020C85F0020D85F0020D7 +:10916000D45F0020D65F00202DE9F743294D2B88DE +:109170008B4206460C46174647D34FF000080DF1C8 +:1091800007008DF8078000F0EDF9234B234A18788B +:109190001178CBB2224909888B4238BF0133C0B263 +:1091A00038BF5FFA83F8404528D092F800801378E2 +:1091B000DBB2994286BF0133DBB2002313709DF806 +:1091C000070000F0F3F94FF6FF7398451FD0154BD9 +:1091D0001B6803EBC80943F8387096B18CB1124B89 +:1091E00028881B682246314608FB003003F074FED5 +:1091F000A9F80440002003B0BDE8F0834FF6FF78E3 +:10920000DDE70020A9F80400F5E70920F3E70420D2 +:10921000F1E700BFD45F0020D85F0020C85F0020C6 +:10922000D65F0020D05F0020CC5F0020F8B5124C44 +:10923000124D264622782B789A4200D1F8BD237829 +:109240000F48104A078812680F48DBB219B202EBC8 +:10925000C10C006852F83120BCF8041003FB070071 +:1092600090470A4A23781288DBB29A4286BF0133BC +:10927000DBB200233370DDE7D85F0020C85F002039 +:10928000D45F0020D05F0020CC5F0020D65F00209C +:1092900040684B6898428CBF002001207047000056 +:1092A00037B505460C460A4801A900F0B8FA60B186 +:1092B0000570446001A9064800F0DBFA18B10548C2 +:1092C00000F05EFA002003B030BD0420FBE700BFD1 +:1092D0003C600020905B002038B5104B1D780446A0 +:1092E000A5B1C0B1037D03F0FF057BB1D0E9033028 +:1092F0009847A36863B1227D02F0FF0542B162681E +:10930000074813446360214600F0C1FD284638BD7C +:1093100000252575FAE70546F8E700BFE05F002065 +:10932000D4D30F002DE9F743054600F01AFA0028C0 +:1093300048D10021284600F019FA38B1574C23686B +:1093400023B12068FFF7C8FF0023236001A9544818 +:10935000DFF84881534EDFF8549100F09AFA044642 +:10936000002C4ED14F4F4D4CDFF84481384600F071 +:10937000A4FD002800F08780426823685B682168AC +:1093800051B12168D9B19A4219D223681B7D1BB112 +:109390002168384600F07BFD384600F088FD4FF428 +:1093A0007A73064642680021404600F089F9002899 +:1093B00062D1236813B9284600F07AF9266003B019 +:1093C000BDE8F083354A13682BB113685B681268F7 +:1093D00023F07F435360334800F06FFD04460028BC +:1093E000A7D06368B3F1807F06D22046FFF774FFF1 +:1093F000204600F065FDF1E7636823F07F4363607A +:10940000F6E72378012B2AD04BB1022B1DD1002483 +:10941000304600F04CFD00283CD00475F8E7636846 +:109420001A7D92B901221A75636828465F6800F0B8 +:10943000A3F9381A484581BF6268536823F07F4317 +:1094400053606168304600F022FD01A9144800F025 +:109450004BFA01A9124800F01CFA044680E7D8F83C +:1094600000306168994208BF0023304608BFC8F841 +:10947000003000F027FDE8E70D287FF477AF304695 +:10948000FFF72AFF72E72368002B98D1284600F0E7 +:1094900013F994E7044B01221A70D6E74C600020C0 +:1094A0003C600020D4D30F00E05F002017FCFF00D9 +:1094B000905B002013B50023ADF8043007238DF82E +:1094C0000630582208230B490B4800F073F9044674 +:1094D00068B90A4A0A4801A900F0A8F8044630B958 +:1094E0000121074800F034F9064B01221A7020468A +:1094F00002B010BDE45F00203C60002025930F0007 +:10950000905B0020E05F00203AB10368DA604A1EF9 +:109510005142514199600020704707207047000078 +:1095200038B50B4B994204460D460ED802610948E6 +:1095300000F022F9A3682844606003B1A5602146C9 +:109540000020BDE83840FFF7ABBE072038BD00BFA4 +:1095500017FCFF00905B00200023014603750120EB +:10956000FFF79EBE70B5EFF3108672B60C4A946892 +:1095700001239CB993600B4B0B4DD3F8801029400D +:109580001160C3F88050D3F8841051604FF0FF325F +:10959000C3F88420047006B962B670BD0370FAE7A0 +:1095A0005060002000E100E0FC06FFBD10B5084B54 +:1095B0009A685AB150B9EFF3108172B6054A1C6827 +:1095C00014605C685460986001B962B610BD00BF59 +:1095D0005060002000E100E030B53AB11368DB4391 +:1095E0000A4D0144884204D1D84330BD4FF0FF33C7 +:1095F000F6E710F8012B5340082213F0010418BFBE +:109600002C46013A84EA5303F7D1EBE72083B8ED07 +:10961000435882B03BB10023435043580193019B10 +:10962000012002B070471846FBE7000010B51D4C42 +:10963000437944F823201C4C04EBC3031B797BBB08 +:1096400003680A88C3F8082590F904308A78002B4B +:109650004FEA4212AFBF03F1604303F00F03134917 +:10966000D2B2A9BF03F56143CA54D2B283F8002332 +:1096700090F9043003F01F025B099B0003F1604383 +:1096800003F56143012101FA02F2C3F880211A6057 +:10969000437904EBC30244F833001171002010BD7C +:1096A0000820FCE7646000205C60002014ED00E00E +:1096B000036801221A607047036801225A607047EC +:1096C000F7B51F464FF4803503688D40C3F8085343 +:1096D0000368044601F15000C3F848538000236832 +:1096E00080B222F07F4600221A501B580193019B42 +:1096F000236803EB8101D1F84025C1F84065236858 +:10970000D3F80435D21A22F07F42012A05D10F4B3B +:109710004FF4046043F0010398472368C3F84453AF +:109720002368D3F80425B61A26F07F42310248BFD9 +:1097300042F07F427F42974201DA022A04DDC3F8F9 +:109740000453002003B0F0BD0D20FBE7E0D30F0071 +:1097500002680223C2F8443311B10268C2F804332C +:1097600070474FF482710068FFF752BF5031890093 +:1097700089B20068FFF74CBF0368D3F8040570474F +:1097800090F9043001215A0903F01F0301FA03F391 +:109790004032024941F82230704700BF00E100E04A +:1097A000024B034A1B681068184700BF6460002022 +:1097B0005C60002010B561B1B2FBF3F403FB14242C +:1097C000A4B244B9C0E9001484608281C3812046F8 +:1097D00010BD0E20FCE70920FAE782B050E8022F06 +:1097E000C188B2EB324F4FF0000317BF92B241EA8B +:1097F000014142EA014104E04268B2EB324F08BF46 +:10980000012340E80212002AE8D18DF807309DF8C4 +:109810000730002B0CBF1120002002B0704737B575 +:1098200050E8013F9DB2C48925448489A54228BFE0 +:109830002D1B0489A54202BFBFF32F8F002207E032 +:10984000C5EA030540E80154002CE9D14FF00102BC +:109850008DF803200193019B9DF803200B6002F01B +:10986000FF0322B10B880068184403B030BD1846CE +:10987000FBE70A884B889A4209D150E8012FC2EAD7 +:10988000024240E80123002BF7D10120704700205D +:10989000704737B550E8023F1FFAA3F5C488A542C8 +:1098A00002BFBFF32F8F00220DE0C48925448489B5 +:1098B000A54228BF2D1BC3EA054540E80254002CF1 +:1098C000E8D14FF001028DF803200193019B9DF830 +:1098D00003200B6002F0FF0322B14B88006818449C +:1098E00003B030BD1846FBE70A884B889A4209D17D +:1098F00050E8022FC2EA224240E80223002BF7D1AF +:10990000012070470020704750E8002F42EA010311 +:1099100040E8003C9CF0000FF6D11046704750E83C +:10992000003F03EA010240E8002C9CF0000FF6D152 +:10993000104670470121FFF7E7BF0021FFF7EFBF97 +:1099400010B590B1D0E9012301689B1ADBB20A601F +:10995000013BDBB2FF2B026802D10020107110BD69 +:1099600011684C1C14600B70F2E70E20F7E737B556 +:10997000054600240DF107008DF80740FFF7F2FDC2 +:109980002A68696813688B4210D9591E116013F850 +:10999000014C2A8AEB6802FB04342A68AB68116820 +:1099A0005B1A1179DBB2994238BF13719DF8070039 +:1099B000FFF7FCFD204603B030BD37B50546002358 +:1099C0000DF107000C468DF80730FFF7CBFD2A6834 +:1099D0001368591C1160E968641A298AB4FBF1F410 +:1099E0001C709DF80700FFF7E1FD03B030BD01607A +:1099F0000B681146184710B40468E468A4465DF883 +:109A0000044B604710B404682469A4465DF8044B15 +:109A10006047000070B508B10368ABB90C4D0D4C40 +:109A20000026641B1423B4FBF3F4B44201D10020DC +:109A300009E02B6813B901361435F6E7DB692846CF +:109A400098470028F7D070BDDB69BDE87040184723 +:109A5000AC5B0020C05B0020014B436000207047DE +:109A6000E8D30F000846704700207047024B186883 +:109A7000003018BF012070476860002008B5024818 +:109A8000FFF75BFF002008BD6860002008B51046A6 +:109A90001A4603F021FA002008BD00002DE9F0412C +:109AA000804686B013480E4615461F46FFF742FF14 +:109AB000044630B111200EE006EB043000F034FB18 +:109AC0000134A542F8D10B48FFF737FFD8F808302A +:109AD00000241BB9184606B0BDE8F0810222684692 +:109AE0008DF80020CDE90146CDE90345059798475B +:109AF0002046F0E7686000202DE9F041804686B0FE +:109B000012480F4616461D46FFF714FF0446D8B903 +:109B1000AA083146384600F01FFB0C48FFF70DFF3E +:109B2000D8F808301BB9184606B0BDE8F08101220C +:109B30008DF800200C9A05926846CDE90147CDE9E1 +:109B4000036598472046EFE71120EDE768600020A5 +:109B500029DF704728DF704770B50568AB6886B0AD +:109B600004460E4673B1142200216846FDF7DAFB65 +:109B7000A36805932379019633B1012B0ED0AB680E +:109B80006846984706B070BD01238DF80030236900 +:109B90000293E368039363690493F0E702238DF86B +:109BA0000030E3681B030293F5E708467047002086 +:109BB00070470000024B187A003018BF0120704730 +:109BC00058620020034B187A0122B0FA80F05A74D0 +:109BD000400970475862002008B510461A4603F045 +:109BE0007BF9002008BD000008B5142200210448BC +:109BF000FDF798FB0348FFF7F0FD002008BD00BF0C +:109C0000586200204862002010B5094C094B43609F +:109C10002046FFF78FFE48B900F09AFB1C23207402 +:109C20004FF4EE7204490548FFF7C4FD002010BD53 +:109C30005862002014D40F006C600020486200209D +:109C400070B5234D234E2B7A2C463BB9224923482D +:109C5000FFF71FFE306008B9686070BD02232372F1 +:109C600033681A7972B1012A22D018460321FFF70E +:109C700073FF00232372636017491848BDE87040E2 +:109C8000FFF732BED3E90520121A142A28BF142286 +:109C9000D3E903159208012A014438BF0122284460 +:109CA000FFF756FF50B11128DFD101232372D4E70B +:109CB000D3E903021044FFF74DFFF3E7237C002BA9 +:109CC000CBD10146BDE87040022000F009B800BFCA +:109CD00058620020706200206C6200204862002000 +:109CE00038B5831E012B43D8224C237A002B3FD05A +:109CF000022B09D103282ED01F4B00221B68E260E3 +:109D00001A793AB1012A20D0637C6BBBBDE8384098 +:109D1000FFF796BFD3E905128D1A142D94BF52197F +:109D200014329A619142EFD102284FF0000308BF2C +:109D300019462372104B18BF0D211868FFF70CFF4E +:109D40000E490F48FFF7D0FDDEE71A6901321A61AC +:109D50005B699A42E7E7E3680133082B01D8E360C7 +:109D6000D2E70023E360DFE7BDE8384000F0E0BA67 +:109D700038BD00BF58620020706200206C62002075 +:109D80004862002000F0FD03012B08D1044B0022A3 +:109D90005A74421E504250411874FFF751BF704729 +:109DA0005862002010B5064C201DFFF7C3FD28B9EE +:109DB000637C1BB9BDE81040FFF742BF10BD00BF78 +:109DC000586200202DE9F34180460D46104801A954 +:109DD00016461F46FFF723FD0446B0B118220021A6 +:109DE0000430FDF79FFA2D0B0123237101A9C4F85C +:109DF0000080A760E56066610548FFF73AFDFFF760 +:109E0000D1FF002002B0BDE8F0810420FAE700BFD6 +:109E1000486200202DE9F74381468846104801A991 +:109E200017461E46FFF7FBFC0446B8B11822002176 +:109E30000430FDF777FA00250A9BA36001A925717C +:109E4000C4F80090C4E9037866610548FFF711FD86 +:109E5000FFF7A8FF284603B0BDE8F0830420FAE727 +:109E60004862002001600B6843604A68934204BF67 +:109E7000002343607047436843B1026891680B4414 +:109E800043605268934204BF00234360704770B53B +:109E9000446806460D46206818B1B36829469847BD +:109EA00018B923682B60256070BD2468F3E7436808 +:109EB000186808B102681A607047436818687047EC +:109EC000006870474368186800B97047884203D13A +:109ED00002681A600120704703460068F4E700003A +:109EE000054B1B68082B01BF044B1868B0FA80F0C3 +:109EF000400918BF002070473001001034010010E5 +:109F000008B54FF080430022C3F80C21C3F810219C +:109F1000C3F838254FF0805203F54043D2F80414BB +:109F2000C3F82015D2F80814C3F82415D2F80C147D +:109F3000C3F82815D2F81014C3F82C15D2F814144D +:109F4000C3F83015D2F81814C3F83415D2F81C141D +:109F5000C3F84015D2F82014C3F84415D2F82414DD +:109F6000C3F84815D2F82814C3F84C15D2F82C14AD +:109F7000C3F85015D2F83014C3F85415D2F834147D +:109F8000C3F86015D2F83814C3F86415D2F83C143D +:109F9000C3F86815D2F84014C3F86C15D2F84424FD +:109FA000C3F87025FFF79CFF10B1334B334A1A609A +:109FB000FFF796FF18B1324BFB22C3F81825FFF7C5 +:109FC0008FFF48B12F49304B0A681B6822F00F02FF +:109FD00003F00F0313430B60FFF782FF18B12B4B05 +:109FE0004FF400721A604FF08043D3F80024D20778 +:109FF00044BF6FF00102C3F80024254AD2F888302C +:10A0000043F47003C2F88830BFF34F8FBFF36F8FF4 +:10A010004FF01023D3F80C32DB0729D51D4B01225A +:10A02000C3F80425D3F80024002AFBD04FF01022F7 +:10A03000D2F80C3223F00103C2F80C32154B1A4649 +:10A04000D3F800140029FBD00021C3F80415D2F87E +:10A050000034002BFBD0BFF34F8F0D490E4BCA6865 +:10A0600002F4E0621343CB60BFF34F8F00BFFDE704 +:10A070000A4B0B4A1A6008BD8C5600404881030009 +:10A0800000F00040E40E00405802001040960240EC +:10A0900000ED00E000E001400400FA05985B0020BC +:10A0A0000090D00343689B68184770B54668044623 +:10A0B0000D46FFF7F7FF04F108007279294600F01A +:10A0C0000CFB002070BD2DE9F0430D469BB0084607 +:10A0D00099469046FFF7E6FF6E6874794C4528BFB5 +:10A0E0004C4607462246414602A800F0EBFA727938 +:10A0F00022990AA800F0F1FA00970AAB224602A9B9 +:10A1000005F10800FEF706FD002848F2425018BF8E +:10A1100000201BB0BDE8F083024AD2F80034002BC7 +:10A12000FBD0704700E001400A4908B50223C1F89E +:10A130000435BFF36F8FBFF34F8FC1F80805FFF7EA +:10A14000EBFF0023C1F80435BFF36F8FBFF34F8FD0 +:10A1500008BD00BF00E001400E4B10B50124C3F85C +:10A160000445BFF36F8FBFF34F8F01EB8204401A9A +:10A17000A14208D1074B0022C3F80425BFF36F8F1B +:10A18000BFF34F8F10BD431851F8042B1A60FFF72F +:10A19000C3FFEDE700E0014010DF704711DF7047BB +:10A1A00013B5044609496846FFF75CFE019808B9F3 +:10A1B00002B010BDD0E900312046984718B168467A +:10A1C000FFF759FEF2E71120F2E700BF50D40F006D +:10A1D00013B5044607496846FFF744FE019B0BB9D7 +:10A1E00002B010BD2046D3E9002190476846FFF732 +:10A1F00042FEF3E768D40F00064B9A6822B11A6852 +:10A2000022F480021A607047034B4FF48002C3F8B7 +:10A21000802070475060002000E100E00B4A92F877 +:10A2200016335B09012B08D9042B06D0084B99681B +:10A2300039B94FF480031360704742F20200FDF712 +:10A240002EBB1A6842F480021A60704700E100E0F9 +:10A2500050600020F7B5194F3C7864BB184E0125BB +:10A2600020463570FFF79CFF112821D02046FFF7CC +:10A27000AFFF144B8DF80340186801900DF10300F7 +:10A28000FFF770F9104901A8FFF786FF0446B0FAFE +:10A2900080F0400938709DF80300FFF787F93CB95A +:10A2A0000A4B34701C70FFF7B9FF2846FFF790FF88 +:10A2B000204603B0F0BD0824FAE700BF7562002015 +:10A2C000746200204CD40F009D780F00766200204D +:10A2D000F7B5154F3B781BB3144E01203070FFF7D4 +:10A2E0005FFF11284FF000051CD00220FFF770FF20 +:10A2F0000DF107008DF80750FFF734F9FFF74EFF17 +:10A3000004469DF807003D70FFF750F92CB93470F2 +:10A31000FFF772FF0320FFF75BFF204603B0F0BD9D +:10A320000824FAE72C46F8E77562002074620020E2 +:10A33000054B1B7833B1054B1B780BB1FFF7C8BF3A +:10A34000FFF788BF08207047746200207562002004 +:10A35000014B1878704700BF7562002007B50849A7 +:10A360006846FFF77FFD019B13B903B05DF804FB5E +:10A37000D3E9002090476846FFF77DFDF3E700BF73 +:10A380005CD40F00FFF7EABF60DF704769DF7047FA +:10A3900061DF704730B5104DC7B04FF486740DF1D2 +:10A3A000020103A8ADF80240FFF7F2FF70B9294699 +:10A3B00001A8FFF757FD029B002BF0D003A8D3E9BB +:10A3C0000021904701A8FFF756FDF4E7052801D0CA +:10A3D000FDF765FA47B030BD74D40F00024B1B780F +:10A3E0000BB1FFF7D7BF70477762002018B1034B5E +:10A3F0000360002070470E20704700BFB857002050 +:10A400007FB506460C46002947D0254A0A6000233E +:10A410000621CDE9013301258DF80400ADF80810BF +:10A42000202001A903938DF80650FFF7AFFF2268A3 +:10A43000039301A94020CDE901338DF80550FFF7C2 +:10A44000A5FF8322CDE9013301A9ADF80620232021 +:10A45000226803938DF80460FFF798FF2268039346 +:10A4600001A92846CDE901338DF80450FFF78EFF8E +:10A470004FF4B062019201A92268A120CDE9023314 +:10A48000FFF784FF2268039301A9A020CDE90133DF +:10A49000FFF77CFF184604B070BD0E20FBE700BF3D +:10A4A000B857002008B5FFF76FFF10B9014B012224 +:10A4B0001A7008BD776200204BDF70471FB50D4C46 +:10A4C00001A8FFF7F9FF70B9214602A8FFF7CAFCFF +:10A4D000039B002BF4D00198D3E90021904702A8F8 +:10A4E000FFF7C9FCF4E7052801D0FDF7D8F904B05F +:10A4F00010BD00BF80D40F0028B139B10023C1E9DD +:10A5000000301846704748F21050704748F2135018 +:10A51000704730B1036848F240508B4208BF0020BA +:10A52000704748F21050704728B148F211509142DC +:10A5300008BF0020704748F21050704770B50646BB +:10A540000C461D46FFF7D8FF50B9B3794AB1AB426C +:10A550000AD111462046FFF7A8FD08B9044B236035 +:10A5600070BD48F21050FBE748F21150F8E700BF09 +:10A570007052464D2DE9F0470C4607460F492046DC +:10A5800015469846DDE90869FFF7C3FF98B9636887 +:10A590005A79494652003046FFF7C6FF58B945B1CF +:10A5A000089643462A4621463846BDE8F047FFF75D +:10A5B0008ABD48F21050BDE8F08700BF7052464D8A +:10A5C00010B5044638B149B141600B68984708B9E5 +:10A5D000044B236010BD48F20150FBE748F21050D5 +:10A5E000F8E700BF6E524648F0B448B107680A4E1B +:10A5F000B74209D159B16AB14368F0BC5B681847EA +:10A6000048F20150F0BC704748F20250FAE748F2B5 +:10A610001050F7E71046F5E76E524648F0B460B1C7 +:10A6200007680C4EB7420CD171B143681568DC68FD +:10A63000A5420CD39B68F0BC184748F20150F0BC0F +:10A64000704748F20250FAE748F21350F7E748F231 +:10A650001450F4E76E5246482DE9F041044617467F +:10A660009846DDE90656FFF7ABFF60B9424639462A +:10A670002046FFF7B9FF30B9324629462046BDE8EB +:10A68000F041FFF7CBBFBDE8F0810000F8B50A4FFD +:10A690000A4C0B4DE41B0121E40829700026A64258 +:10A6A00003D102232B700020F8BD57F836309847AD +:10A6B0000028F9D10136F2E7FCD50F00FCD50F00D8 +:10A6C00078620020013A02440139824200D2704788 +:10A6D00011F8013F02F80139F7E770B516460D464B +:10A6E000FFF7F0FF3246A9193044BDE87040FFF78C +:10A6F000E9BF000070B5144B144A0C21D21AB2FB0A +:10A70000F1F2816911F8025C044635B90069002153 +:10A71000914205D1012323600EE04FF0FF30F6E7B0 +:10A720001E68AE420CD1461C07D19D68D4E90001D9 +:10A73000D4E90223A847206070BD5E688642F4D049 +:10A7400001310C33E4E700BF18D60F0024D60F0008 +:10A750001EF0040F0CBFEFF30880EFF30980FFF742 +:10A76000C9BF00BF007800F0010070470023C0E9B6 +:10A770000232C0E900118B781A44026191F903306A +:10A780001A4442610878003018BF0120704710B5A4 +:10A7900042681178034600293AD002F10C01416069 +:10A7A000147B2CB9C2680168FFF7E0FF204610BD9A +:10A7B0005078117900F03004302C1BD1547B04F018 +:10A7C0003004302C1ED190781969091A19610021C2 +:10A7D000507810F0300F02BF986801309860907B7D +:10A7E000084419690144196192F90F201144596113 +:10A7F0000120DCE700F0F004202C03D1507910FB9D +:10A8000001F1E5E700F0C000802808BF0421DFE780 +:10A810000846CCE770B5456804460E4663681A786A +:10A82000B24204D15B7803F00F03082B07D1204616 +:10A83000FFF7ADFF6368AB42F0D1002070BD01208F +:10A84000FCE743681A44426011B101399A4201D1D0 +:10A850000120704713F8010B01F8010FF6E770B5FE +:10A860004268527802F00F01082986B003461FD1D2 +:10A8700003691C6800260CB906B070BD23682673F6 +:10A880009D68626829466846FFF770FF6368049315 +:10A8900004F10C0305936B7803F0C003802B08BF11 +:10A8A000231D684608BF0493FFF7D9FFA468E2E7B9 +:10A8B00012F0C00120D102F0300010280ED15A69E8 +:10A8C00011705A6818695378946803F00F03072BC6 +:10A8D00009D10146204600F017F8CDE79006F0D5E3 +:10A8E0005B691970C8E71279214614B102F0F4FAD5 +:10A8F000C2E7FCF717FDBFE78029BDD10069002141 +:10A9000092060160B8D5EBE77FB50A460146684676 +:10A91000FFF72CFF30B16846FFF7A1FF6846FFF74D +:10A9200036FFF7E707B05DF804FB10B501220368B6 +:10A930000446984710B1A368013BA36010BD2DE900 +:10A94000F34183680746884623B90026304602B0A3 +:10A95000BDE8F0810DF10701FFF7E7FF064600288B +:10A96000F3D09DF80740220616D504F07F04072592 +:10A97000BB68002BE9D00DF107013846FFF7D5FF82 +:10A980000028E2D09DF8072002F07F03AB401C4373 +:10A99000130605F1070502D4C8F80040D6E7232DB9 +:10A9A000E6D1D2E730B5044685B01546A9B90268AC +:10A9B000114B9A4211D0102D06D82A4669462046DE +:10A9C000FFF7F0FF05B030BD102269462046FFF7C3 +:10A9D000E9FF0028F6D0103DEDE7A368AB4201D2B5 +:10A9E0000020EFE723682A46204698470028F7D042 +:10A9F000A3685D1BA560E5E743A80F00F7B50E4609 +:10AA000001A907461546FFF79AFFA8B1019A01234D +:10AA1000D3184FF0000404D2717801F0C0018029EE +:10AA200001D1204608E031799942FAD329463846C7 +:10AA3000FFF7B8FF019BEC5403B0F0BD73B50D46B2 +:10AA400001A906461446FFF77AFF90B1019AFF2A42 +:10AA500011D86B7803F0C003802B02F101010AD0FA +:10AA60002B798B4207D32146304601F8012BFFF7A3 +:10AA700099FF02B070BD0020FBE7000010B5034C49 +:10AA800082600022C0E90041C26010BD43A80F00EF +:10AA90002DE9F347002580460F462E462C46D8F870 +:10AAA000083023B30DF107014046FFF73EFFF0B138 +:10AAB0009DF807C00CF07F025FFA82F9A4F1200331 +:10AAC000C4F1200109FA03F329FA01F109FA04F2A9 +:10AAD0000B431CF0800F45EA020546EA030604F129 +:10AAE000070402D1C7E9005602E0462CD7D1002066 +:10AAF00002B0BDE8F08773B50C4669461646FFF70D +:10AB0000C7FF68B12379082B0CD1DDE90045C6E900 +:10AB10000045DDE90023AB4206BFA2420120002030 +:10AB200002B070BD042B04D1009B33601C4600258D +:10AB3000EFE7022B4FF0000004D1009B33809CB262 +:10AB40000546E6E7012BEBD1009B337003F0FF04D1 +:10AB5000F6E737B50D4669461446FFF799FF30B161 +:10AB60002A79082ADDE9003103D1C4E9003103B0B4 +:10AB700030BD042A18464FEAE37108D123601A4613 +:10AB80000B468B4206BF824201200020EFE7022ADB +:10AB900004D11BB223801AB2D317F2E7012A03D1E2 +:10ABA0005BB223705AB2F7E70020E0E7F7B50C4636 +:10ABB000002119702170116001A9074615461E4633 +:10ABC000FFF7BDFE30B9BB6813B901233370002015 +:10ABD00003B0F0BD01990029F7D0CB0801F00701BF +:10ABE0002B602170F4E713B5044605291FD8DFE870 +:10ABF00001F0030F151E1E1C012201A92046FFF7BC +:10AC0000D1FE18B19DF90430002BF5DB02B010BD68 +:10AC1000082200212046FFF7C5FEF7E701A9FFF74C +:10AC20008EFE0028F2D0019AF3E70422F1E700201B +:10AC3000ECE773B50D4601A90446FFF780FE064612 +:10AC400018B90026304602B070BD94E80F0085E8C0 +:10AC50000F0001998A42F4D3A960A3685B1AA3602C +:10AC6000F0E700002DE9F04355686B7813F0C0045D +:10AC700089B006468C46174603D0402C6AD0002483 +:10AC80000AE003F00F025E4903F03003102B51F885 +:10AC9000228020D004D8CBB1204609B0BDE8F08393 +:10ACA000202B1ED0302BF7D17B6929781970072A09 +:10ACB0000AD17B6838691A792146FCF733FB7B6837 +:10ACC00039699868FFF720FE3A6940E03A692946F9 +:10ACD000C0470446E0E77B6901221A703A69796847 +:10ACE000F6E7BCF1020FD7F8149024D1042A22D839 +:10ACF00004A9FFF79EFF04460028C0D0069B2BB195 +:10AD0000796899F800304A799A4205D8059B7360B2 +:10AD1000069B002BC0D0B2E708793A6900FB0322FA +:10AD200004A8C04728B199F80030013389F80030F1 +:10AD3000E4E70446EAE799F800306A799A429ED936 +:10AD40003A692979581C89F8000001FB03227968C7 +:10AD50003046BDE7D2F81080454655F8043B13B99C +:10AD6000FFF741FFB5E7022914D104A9FFF761FFFE +:10AD7000002884D0D8F8003079682A4604A898477B +:10AD8000044600283FF47BAF069B002BF2D1059BC5 +:10AD9000736081E701292BD04CB24CB105297FF4B7 +:10ADA0006EAF04220DEB0201FFF7FCFD042424E04A +:10ADB0000DF1040901340B2C3FF461AF0122494627 +:10ADC0003046FFF7EFFD00283FF459AF19F9013B7A +:10ADD000002BEFDB0B4B049301ABCDE905340023D3 +:10ADE0000793D8F8003079682A4604A8984770E796 +:10ADF000082201A9FFF7D6FD08240028EAD13EE782 +:10AE00008CD40F0043A80F002DE9F04F91B00446F9 +:10AE1000002604A8CDE90266FFF7A8FCA3683BBBA7 +:10AE2000DDE9053404A85D78FFF7B1FC0028F7D10F +:10AE300015F0300F03D1059B1B7803B10134002CB2 +:10AE400000F0A9806309002202A9934240F09C808F +:10AE500010AA02EB830304F01F04C4F120044FF096 +:10AE6000FF3053F8383CE040C31A584258410DE0D7 +:10AE70000DF1030301AA0DF102012046FFF796FE32 +:10AE800038B99DF80330002BCAD1002011B0BDE8BD +:10AE9000F08F019904A8FFF7BDFC002850D1019B59 +:10AEA000B3427DD3059D059A537803F00F03082B19 +:10AEB0007FD004A8FFF76BFC059B9D42F3D14FF0B8 +:10AEC000FF36019FB7426BD3089B9DF80290D4F8E0 +:10AED00008801D684FF0010AA368002D5DD09845D9 +:10AEE0009CD12B68D3F800B0BBF1000F08D04B46C3 +:10AEF0003A4629462046D8470028C6D0AD68EBE739 +:10AF0000D3F808B09BF800309F42F7D16A685946E1 +:10AF10000AA8FFF72BFC6B680E9305F10C030F9347 +:10AF20009BF8013003F0C003802B04BF2B1D0E9350 +:10AF30000AAA85F80CA049462046FFF793FEDBE7F6 +:10AF4000059B5B7813F0300F0FD1069A3F2A0CD87F +:10AF5000510910AB03EB810102F01F020123934062 +:10AF600051F8382C134341F8383CE5682DB104AB57 +:10AF70009DF8022001992046A84704AA9DF80210D6 +:10AF80002046FFF76FFE10E051F8225001357FF4A4 +:10AF90007DAF013259E7012078E798457FF43EAF55 +:10AFA0009DF802102046FFF71EFE00287FF436AF02 +:10AFB0006BE7167885E770B50C46064615461146D0 +:10AFC0002046FFF7A1FC2A4621463046BDE87040E6 +:10AFD000FFF71ABFF0B585B00C468D686946074685 +:10AFE0001646FFF726FE68B1A06858B1637803F0F3 +:10AFF0003003202B32462946684605D1FFF7DBFF98 +:10B00000019B7B6005B0F0BDFFF7FEFEF8E7D3B50E +:10B010000C466946FFF73CFD80B1DDE900130027CF +:10B020004A0801F0010642EAC37256EA07014FEAF4 +:10B0300053031CBFD243DB43C4E9002302B0D0BD9D +:10B0400037B50D4669461446FFF7E1FF68B12B7925 +:10B05000082B0CD1DDE90001C4E90001DDE9002382 +:10B060008B4206BF82420120002003B030BD042B7A +:10B0700003D100982060C117F0E7022B04D1BDF97D +:10B080000000208000B2F6E7012B04D19DF90000FA +:10B09000207040B2EFE70020E7E713B504220C462A +:10B0A0000DEB0201FFF77EFC08B1019B236002B0AB +:10B0B00010BD1146FFF7F1BF13B508220C466946D3 +:10B0C000FFF770FC18B1DDE90023C4E9002302B0EA +:10B0D00010BD1146FFF7F0BF062810B5044602D197 +:10B0E000002000F06DFF044B1B681BB12046BDE83B +:10B0F0001040184710BD00BF7C62002008B5074B08 +:10B1000018600020FFF7E8FF054800F041FF20B974 +:10B110000348BDE8084000F063BE08BD7C62002023 +:10B12000D9B00F006CDF70476DDF704772DF70477A +:10B1300073DF704774DF704775DF704776DF7047E5 +:10B140007ADF70477CDF70477DDF70477FDF7047B5 +:10B1500086DF70478FDF704790DF7047A8DF70474A +:10B16000AADF7047ADDF7047AEDF7047B0DF7047D2 +:10B17000B1DF7047B5DF704762DF704766DF704749 +:10B1800013DF70477FB50023CDF80A30ADF80E30DD +:10B190000A4BADF806109B89ADF8083001238DF8F5 +:10B1A0000A300DF10603CDE90430054B02A91888D9 +:10B1B000FFF7DAFF07B05DF804FB00BF467300201D +:10B1C0009E5B002001460148FEF7F7BB04D60F0046 +:10B1D00030B518228DB000210DEB0200FCF7A2F86B +:10B1E000282308931623ADF806300023CDF80E303F +:10B1F000CDF81230ADF816301A4B02930222062118 +:10B2000009251A7099701A71032159220124D970E5 +:10B210005A710DF10601FE2258198DF818408DF86B +:10B220002D40ADF80C505C709A71FFF78DFFB8B9E6 +:10B23000BDF806201D721119D971BDF80C301A44E1 +:10B24000094BADF80C2002A906AA1846FFF76EFFBD +:10B2500030B91878FFF76EFF21461878FFF768FFBE +:10B260000DB030BD5A7300209C5B0020F0B5038800 +:10B270001F2B8BB0044600F0C28029D8112B56D06A +:10B2800006D8012B00F0CC80102B42D00BB0F0BDC3 +:10B29000142B00F040811A2B34D0132BF6D100234D +:10B2A000A04CADF812300223ADF8103004AA02AB66 +:10B2B00042F6052120880593FFF754FF08B1FCF7FB +:10B2C000EEFA00231A4685212088FFF73FFF86E02B +:10B2D000512B00F0AB800ED8232B00F08880502B30 +:10B2E00039D0212BD2D1002304A98088ADF81030A9 +:10B2F000FFF730FF73E0552B59D0562B00F08680B6 +:10B30000522BC3D100231A461946A088FFF730FFFD +:10B3100065E0844B82881A80834A12681C460AB111 +:10B320000120904781492088FFF706FFAEE77D4B5B +:10B330004FF6FF721A807E4B1B685A0704D4FFF742 +:10B3400047FF08B1FCF7ABFA774B1B68002B9DD089 +:10B35000022098479AE7774EC288B3889A4295D1DF +:10B360007548FEF704FB054600288FD0228A04F1B9 +:10B37000120101F0B1FD1822002104A8FBF7D2FF51 +:10B3800008238DF810306D4B06936D4B0596CDE973 +:10B39000073504A8238AADF8243000F017FD0028F3 +:10B3A0003FF474AF29466448FEF707FB6EE7C18897 +:10B3B00082291AD8CB1E9B070DD0CB1F9BB2013B15 +:10B3C0005A4202F0030203F0030301F1FF3158BFB8 +:10B3D0005342C91A89B2534B1888FFF7CBFE002895 +:10B3E0003FF454AFFCF75BFA50E78321F3E7002208 +:10B3F00004A98088CDE90422FFF7AEFEEFE7494BB0 +:10B4000000F108011888FFF797FEE8E78379002B21 +:10B410007FF43CAF434B13211888FFF78FFEDEE724 +:10B42000404B00211888FFF7A9FED8E78379002B4D +:10B430003FF42CAF022B7FF429AF3E4900898A8963 +:10B4400090420E467FF422AFA27B012A7FF41EAF0A +:10B4500000220120CDE904228DF81600208AADF8E3 +:10B460001800304D608AADF81A0004F114008DF810 +:10B4700010300790ADF80A20ADF8083002AA01ABF1 +:10B48000098A28880393FFF76DFE2F4660B9184696 +:10B49000FFF768F940B940F2FD1304A92888ADF818 +:10B4A0001430FFF763FEF1E6002304A93888ADF8F5 +:10B4B0001430FFF75BFE014600287FF4E7AE182248 +:10B4C00004A8FBF72FFF237D1C4A8DF81030022BB8 +:10B4D0000596069216D0062B0ED0012B0ED11948D8 +:10B4E00000F06EFD184B1A88184B1A80637D089384 +:10B4F000D4F81630099301E0637D089304A800F0A6 +:10B5000065FCC3E6A27D637D43EA02230E4A1380F5 +:10B510000E4A1380F2E700231A4619468088FFF787 +:10B5200017FE5CE79E5B002080730020E6D50F00CD +:10B530007C7300204673002004D60F00B9B50F00BD +:10B54000C5B10F00FCD50F00847300208673002066 +:10B5500038B514490A6812F0010321D0124B984201 +:10B560001ED0124B18884FF6FF73984213D042F04A +:10B5700004020A601321FFF7E1FD90B90C4DC824C5 +:10B5800045F001054FF47A40A847013CFAD1BDE8E7 +:10B590003840FEF79DBE074B1878FFF7CBFDF6E766 +:10B5A000002038BD7C730020FCD50F009E5B00207E +:10B5B000E0D50F009C5B002010B5044686B0112238 +:10B5C000002101A8FBF7AEFE2378082B0BD1374AE8 +:10B5D000374913880988013B9BB21380D9B1D3B98D +:10B5E000032311802370627823788DF80530602161 +:10B5F000012A8DF804108DF806200ED00B2A12D1E6 +:10B6000000F0C8F98DF80700002000F0BDF9042112 +:10B6100001A8FFF7B7FD06B010BD062B05D0082B1B +:10B6200029D0032B27D00321F2E7E1688DF807101A +:10B63000D4E90123080A8DF80800080C090E8DF8DA +:10B640000A10110A8DF80B208DF80C10110C120E37 +:10B650008DF80E201A0A8DF80F308DF810201A0C74 +:10B660001B0E8DF80D108DF809008DF811208DF846 +:10B6700012300F21CCE7D4E90123110A8DF80720FD +:10B680008DF80810110C120E8DF80A201A0A8DF888 +:10B690000B308DF80C201A0C1B0E8DF809108DF84C +:10B6A0000D208DF80E300B21B2E700BF867300200D +:10B6B000847300202DE9F043444B95B005464FF6C6 +:10B6C000FF721A8001204FF659632A4602A98DF8AD +:10B6D0000A00ADF80830FFF741FD0446002871D19B +:10B6E0003B4B04AA03F11007164618685968144624 +:10B6F00003C40833BB422246F7D1A91C3046FFF7EA +:10B700003BFD044600285DD101461C220DA8FBF735 +:10B7100009FE9DF83430ADF8044043F004038DF881 +:10B7200034300223ADF80C30AB788DF80E3004F0D5 +:10B73000F80343F003038DF806308023CDE90A4473 +:10B74000ADF82C302B4601AE4FF0110903AF33F8A2 +:10B75000040B0C9408AA0DA98DF80590CDE9087684 +:10B76000FFF7FEFCA046044660BB01461C220DA864 +:10B77000FBF7D8FD9DF83430ADF8044023F01803F2 +:10B7800043F018038DF834300123ADF80C30AB785A +:10B790008DF80E301723CDE90A44ADF82C302B4636 +:10B7A00008F0E80848F0130833F80C0B0C9408AACA +:10B7B0000DA98DF805908DF80680CDE90876FFF784 +:10B7C000CFFC0446204615B0BDE8F0839E5B002008 +:10B7D000C8D50F0030B5314C236813F0010585B092 +:10B7E0005AD12F4B18602F48FEF7AAF8029500F0A7 +:10B7F000ECF800284ED12C48FFF7C2FC002849D1B4 +:10B80000FEF728FD002845D102A8FEF7EFFD00282D +:10B8100040D102A90120FEF7F3FD00283AD102A889 +:10B82000FEF740FE002835D100F08AFB30B11F48FA +:10B8300000F076FB236843F002032360112302A883 +:10B840008DF80430FFF770FC20BB9DF8093002A88A +:10B8500001338DF80930FFF765FCD8B92568AB07CF +:10B860004BBF124912498A69072248BF043192B27C +:10B8700001A8FFF767FC68B90E48FFF761FC48B9FB +:10B880000D48FFF717FF28B9FFF7A2FC10B945F0E4 +:10B890000105256005B030BD0020FBE77C7300206A +:10B8A0008073002004D60F0000700F00806200201B +:10B8B000D8D50F00E6D50F004673002038B1054BF0 +:10B8C0000360054B436001230372002070470E2084 +:10B8D000704700BF03B90F00DDB80F0069B10B78E6 +:10B8E000022B0CD1022804D003280CBF1120082001 +:10B8F000704703230B70002070470E20704708200C +:10B90000704710B50C4681B10B78042B04D8DFE8E2 +:10B9100003F00E05030E0E00112010BD00F0E4FA36 +:10B920000028FAD102232370F7E70E20F5E708205C +:10B93000F3E743690BB1C068184770470449054BEA +:10B940000022904208BF19460348FEF750B800BFD6 +:10B9500020D40F00F4D30F00AC5B002007B5009398 +:10B9600013460A4601460348FEF745F803B05DF862 +:10B9700004FB00BFAC5B002013460A4601460148A9 +:10B98000FEF740B8AC5B0020014B18700B207047ED +:10B9900088730020024B002218781A70704700BF8D +:10B9A0008873002018DF704730B585B00546102237 +:10B9B0000C4668460021FBF7B5FCA40868460195D3 +:10B9C0000294FFF7EFFF05B030BD1FB50023CDE9AE +:10B9D00001330393684602230093FFF7E3FF05B0AA +:10B9E0005DF804FB4FF000534FF480521A600020C2 +:10B9F00070470000014B06201B6818479473002015 +:10BA00000A2803D90B38C0B2FFF7BEBF7047000049 +:10BA100030B5054687B00020FDF7FCFF044630B185 +:10BA2000164A18212846FDF79FFB07B030BD014696 +:10BA300018226846FBF776FC04238DF80030104A84 +:10BA4000104B116D1B68994214D10F4B0F4C1868A5 +:10BA500000F0DEFC8DF80100FFF7D2FF8DF8010049 +:10BA6000D5E9011368469847002CDED0204600F047 +:10BA7000DBF9DAE701238DF80130F1E711BA0F00A5 +:10BA8000987300208C73002090730020F5B90F008C +:10BA900070B5044686B0162200210DF10200FBF7B6 +:10BAA00041FC23788DF8003001228DF801200C2B09 +:10BAB00000F28681DFE813F00D0079000F007900B5 +:10BAC000790084017900700079006E001C002F005D +:10BAD00074008DF80420D4E90113684698479DF856 +:10BAE0000130012B00F061819F4B05201B685BE159 +:10BAF0004FF08053D3F800210192D3F80421029231 +:10BB0000D3F80C2192020492D3F8102192020392EE +:10BB10001B690593DFE743F20403944D18682A6A12 +:10BB20009349884214BF01230223012A227C08BFC3 +:10BB3000013352B902238DF80430EB6802938D4B28 +:10BB40000393C3F57E230493C5E7012A12D18842EB +:10BB500010D14FF440531B78142B8ABF43F21403C7 +:10BB600000231B6802934FF48053039343F20803AE +:10BB70001B68E8E79A4209D201238DF80430AB68CC +:10BB8000029300F065FAAB690390DCE7FF238DF8C0 +:10BB90000430A0E7237CFAE7238AADF804309AE763 +:10BBA000714B07201B68984795E7062B724A01D016 +:10BBB000012B01D1216911701178012904D00229CA +:10BBC00056D0002313709CE0013B072B83D801A2C1 +:10BBD00052F823F0F5BB0F00D7BA0F0065BC0F0079 +:10BBE00035BC0F00D7BA0F005FBC0F00D7BA0F00EB +:10BBF0000DBC0F005C4B03201B689847606900F088 +:10BC00000DFBFFF7FDFE8DF8010064E7A18A2069B6 +:10BC100000F020FBFFF7F4FE544B8DF80100DA6BC7 +:10BC20001B6C0293E3680192002B3FF454AF206930 +:10BC3000984750E75149524800F032FBFFF7E0FEC9 +:10BC400001288DF801007FF446AF002000F0ECF8E9 +:10BC500000283FF440AF0A238DF801303BE74FF452 +:10BC600080730393414BDA6B1B6C0192029332E7B2 +:10BC7000013B072B3FF62FAF01A252F823F000BF84 +:10BC8000A1BC0F00D7BA0F005DBD0F0085BD0F002E +:10BC9000D7BA0F00AFBD0F00D7BA0F0007BD0F0016 +:10BCA00000F0F8FA08B90823D6E762690AB9032355 +:10BCB000D2E7C2F30B0333B12C4B30495B6D0968FB +:10BCC00013448B42F3D1B2F5805F01D90423C3E75B +:10BCD000264B2A49586D096815188D42E3D85A64D5 +:10BCE000DA6C9A6418651863254B61691B6801F664 +:10BCF000FF710022090B1844FFF73EFE00283FF4B5 +:10BD0000EAAE0523A8E700F0C5FA0028CBD0174D0E +:10BD1000A28AD5E914315B1A696C13448B42C6D8E8 +:10BD2000174B2E6B1868D4E903313044FFF716FE29 +:10BD300008B1E3687BE7A28A2B6B13442B63A28ACA +:10BD40002B6D13442B6505F14802A18A2069FDF78C +:10BD500043FC2B6DA86402900193BCE6034B9A6CE4 +:10BD600002921B6DF8E700BF9473002098730020C7 +:10BD7000DBE5B15100700F00A05B00208C73002048 +:10BD8000907300200F4BD3E91402596C821A8A4237 +:10BD900089D19A6C5865002120465964DA64FFF70E +:10BDA00037FE094B1B680420984706B070BD054B51 +:10BDB0009A6C1B6D01934FF48053029203938AE6B1 +:10BDC000022349E7987300209473002083681BB115 +:10BDD000024A1821FDF7C8B90720704791BA0F0031 +:10BDE00038B50546C0B10120FFF7A8FD044648B9A3 +:10BDF00000F0F0F900F04EFA30B9084B00201D6059 +:10BE0000FFF7C2FD204638BD0549064800F048FA54 +:10BE10000128F2D00324F5E70724F3E79473002008 +:10BE20008C7300209073002070B5154D154906469F +:10BE30004FF4DC72284601F041F820B90EB9002019 +:10BE400070BDB047FBE7002201210E48FFF794FDCB +:10BE5000024698B95821281DFDF7BEFB4FF4DC724D +:10BE600028602946084801F037F833464FF4DC7261 +:10BE700005490448FFF772FD0028E0D00320DFE702 +:10BE80009873002000F00F005075002038B5FFF7C0 +:10BE900055FD0546A8B9114C11494FF4DC722046F6 +:10BEA00001F01AF8236801330DD14FF4DC72002140 +:10BEB0000A48FBF737FA012300206360FFF7B4FF5D +:10BEC00048B1032507E02A465821201DFDF784FBD1 +:10BED00023688342E9D1284638BD00BF987300200B +:10BEE00000F00F0029DF704738B50C4D0446D5F837 +:10BEF0009C3178B101330FD1002218210430FDF7B5 +:10BF00006BFB2060214605F5CE700722BDE8384066 +:10BF1000FFF7E8BF0E2038BD0820FCE700F00F0057 +:10BF200050B1064B03F11C0253F8041B40F8041BEC +:10BF30009342F9D1002070470E2070479CF10F000A +:10BF400010B5064C002218212046FDF745FB54F899 +:10BF5000043C1B1A5842584110BD00BFA0F10F000D +:10BF600010B50A4CD4F85C31D4F89C21134001334D +:10BF700009D04FF47F20FEF7D7F8572221464FF41F +:10BF80007F20FEF7E9F8002010BD00BF9873002065 +:10BF9000F8B5094E094CA41B0746E4080025A54244 +:10BFA00001D10020F8BD56F83530384698470028B2 +:10BFB000F8D10135F3E700BFFCD50F0004D60F0020 +:10BFC000F8B5094E094CA41B0746E40800250436C1 +:10BFD000A54201D10020F8BD56F8353038469847C3 +:10BFE0000028F8D10135F3E7FCD50F0004D60F0087 +:10BFF000034A00230360436083601363704700BFFC +:10C000009873002043F204031A68084B9A4201BF58 +:10C0100043F20803186800F6FF7020F47F600CBF3D +:10C0200020F00F004FF48050704700BFDBE5B151A6 +:10C0300008B5FFF7E7FF054B9B69184400F6FF7052 +:10C0400020F47F6020F00F0008BD00BF987300202F +:10C05000FFF7D8BF4FF480507047000010B50B4C6D +:10C06000236A012B0DD170B1E3694BB1FFF7CAFF11 +:10C070000022A169FDF7B0FAE3691B1A5842584142 +:10C0800010BD0020FCE71846FAE700BF98730020B7 +:10C090002DE9F74F2A4C0193DFF8B0B0236ADFF89F +:10C0A000B0900093054616464FF0000843F2040A8C +:10C0B0005FFA88F7012F18D0022F24D0FFF7B8FFBE +:10C0C0008EB1009B013BD3F1000C4CEB030CA9EBB0 +:10C0D0000000A84200D319B3BCF1000F18D0A84249 +:10C0E0001ED2042029E0B446F1E7FFF78BFF019B45 +:10C0F0003BB9DAF80030B3EB0B0C18BF4FF0010C72 +:10C10000E5E7BC46E3E74FF0010C4FF48050DEE773 +:10C1100008F10108B8F1030FCAD1A842E1D300E049 +:10C1200017B10848FFF764FF002101230648C4E95E +:10C130000413FFF75DFF6562084603B0BDE8F08FAA +:10C1400098730020B0730020BC730020DBE5B15170 +:10C1500000400F0030B50E490E4C8A6B85B06D461D +:10C1600028465C31FEF78AFC95E80F0084E80F0052 +:10C17000094B0A4AE36000231360094A0949136026 +:10C18000094A204605B0BDE83040FEF714BF00BFA5 +:10C190009873002044790020ADC10F00A4770020DF +:10C1A000A077002074D50F00C87700205B689A68DC +:10C1B000054B9A4207D1D0E90123044901320A60B4 +:10C1C000034A013B13607047F8D40F00A4770020A6 +:10C1D000A077002010B50C4CA36B63B900230B4A69 +:10C1E0001370FEF753FA4023094A0A490A48BDE88A +:10C1F0001040FEF7A3B9FFF7ADFF0028EED0636A49 +:10C20000003318BF0123EAE798730020DC7900208F +:10C2100010CF0F005479002040D40F0038B50546E8 +:10C2200078B1B0F5807F0ED8084C094B00211C2254 +:10C2300004F13C0019702163FBF774F8A563012039 +:10C2400038BD0320FCE70420FAE700BF9873002004 +:10C25000DC79002070B50E4C0646E06BA36B4218EB +:10C260009A420D4611D85C300A462044314600F00F +:10C2700033FEE36B04F140022B4429463046E3636E +:10C28000FDF7AAF92064012070BD0320FCE700BF80 +:10C2900098730020014B1878704700BFDC790020AC +:10C2A0002DE9FF414C4CD4E90E329A4206460F4626 +:10C2B00040F08D80494B1A7898464AB1FFF7B8FE96 +:10C2C0003060636A3B600124204604B0BDE8F08121 +:10C2D000FFF740FF002840D0414B93F89C101A46CE +:10C2E00011B91B78002B38D0002333603B6092F8E3 +:10C2F0009C404CB13B4C92F83831A4F19905202276 +:10C30000039224B91324DFE72346374DF7E7002BC8 +:10C3100042D103AB0193354B0093354A354B12683C +:10C320001B6835493548FEF797F998BB2378402BB1 +:10C3300030D1334A631C1146413453F8040B42F8A0 +:10C34000040BA342F9D14023CDE90013274A039BF4 +:10C350002C492D48FEF70EF908B10524B4E7281D35 +:10C3600000F00CF901280446AED195F8593088F850 +:10C3700000009BB995F868202AB3E86E48B3002204 +:10C38000386001231146FFF783FED0B9FFF750FE56 +:10C39000306099E70A2497E7162495E713F0010027 +:10C3A00003D095F85A0000B1E86D9B07E6D595F8E3 +:10C3B0006030002BE2D0154B6A6EC3F57E239A42A3 +:10C3C00003D9042480E71846EFE71044D6E7082491 +:10C3D0007AE70F2478E700BF98730020DC7900200B +:10C3E000C877002001790020CC770020A8770020B2 +:10C3F000A4770020A0770020BCD30F00287700206E +:10C400009C79002054790020E079002000700F0012 +:10C410002DE9F0434F4BDFF8608193F89C204E4CA0 +:10C4200085B003F1A4050833002A08BF1D4603ABFD +:10C43000019302460B4606460F464FF02009CDF801 +:10C44000008046494648CDF80C90FEF705F920B12A +:10C4500017254448FFF7CCFD13E04A4605F16F016C +:10C46000404600F02BFD0028F2D195F85530CBB9AD +:10C47000012223626B68E262A360A36CC4E90973C2 +:10C480000125202200213848FAF74CFFF422FF2131 +:10C490003648FAF747FF002328462363A66405B011 +:10C4A000BDE8F08303F00208DB074DD542F2040338 +:10C4B000F15803F1A34303F5471303F2D75399420D +:10C4C00045D1AB6D03F5FF5203F6FF731F32C3F383 +:10C4D0000B03D31A42F20802B2589A4237D343F2FE +:10C4E00004031B688B4219D14FF440531B78142B63 +:10C4F00081BF43F2140318681D4BB0FBF3F006F53F +:10C5000000531B78142B89BF42F214030023F35805 +:10C51000174A88BFB3FBF2F398420FD0B8F1000F6F +:10C5200015D01448FFF764FDAC23E362AB6D636381 +:10C53000B8F1000FA1D06B68E3609EE7B8F1000F7F +:10C5400014BFAC23A523F0E7AA23E362F0E7052597 +:10C550007FE700BFC877002098730020BCD30F008E +:10C5600028770020BC730020D0730020F4730020D3 +:10C5700040420F00B073002008770020F0B590F81B +:10C580005430002B63D090F85530032B5FD890F8CF +:10C590006D20032A59D1027A002A58D0C268342A61 +:10C5A00057D143F20401027C0C682B498C4241D1E3 +:10C5B00022B3416911B300F11004002143F20C06CB +:10C5C000CDB2AA4201D8122017E0358854F8047F72 +:10C5D000AF4201F10101F3D10278002A30D0012BE2 +:10C5E0001E4B426894BF9B68DB6893428CBF00235C +:10C5F0000123002B14BF01201020F0BD9BB9012A9C +:10C60000EAD941690029E7D143F20C0100F1100495 +:10C610000D88194654F8046FAE42DDD00131C9B21D +:10C620008A42F7D1CFE713F1FF3218BF0122002A67 +:10C63000D2D1C8E712B14269002AC4D10278F6E724 +:10C64000012B14BF0F200120D7E71420D5E70F20BE +:10C65000D3E71120D1E700BFDBE5B151987300208B +:10C66000BFF34F8F0549064BCA6802F4E0621343DB +:10C67000CB60BFF34F8F00BFFDE700BF00ED00E0D0 +:10C680000400FA0541DF704708B5FFF7E9FF000035 +:10C69000C31E10B50446042B09D8DFE803F00303DA +:10C6A000080F0F00074947F2305000F0EDF8064B35 +:10C6B0001B682BB12046BDE810401847FFF7D0FF9C +:10C6C00010BD00BF89C60F00047E00200020704707 +:10C6D000274B10B518600020FFF7D8FB40B900F0D9 +:10C6E000ABF9012811D010F0FF0F03D002280ED0B3 +:10C6F000032010BDFBF72AF9002835D1FFF730FCE5 +:10C700000028F5D100F03CF8F2E7FFF7A9FF42F26C +:10C71000107400F015FA174A20211820FCF700FDCC +:10C7200008B1FBF7BCF84FF08043D3F81C2512F09A +:10C73000B10F1EBFD3F81C2502F04E02C3F81C2512 +:10C74000FFF7C4FF0028D3D120460B4900F09CF826 +:10C750000A48FEF7D3FC0028CAD100F023FAFCF700 +:10C7600065FDFFF78FFFF8E747F23054D1E700BFD0 +:10C77000047E0020E479002089C60F0091C60F00D6 +:10C7800008B5094B4FF0FF32C3F88020C3F8802171 +:10C79000C3F88420C3F88421FFF724F94FF48050B4 +:10C7A000BDE8084000F002B800E100E070B588B0D4 +:10C7B000EFF305810023D0E9002083F3148883F38D +:10C7C000108883F3118883F31388C1F3080139B902 +:10C7D00082F308884FF0FF339E46004708B070BDD3 +:10C7E000CDE90033CDE9023304934FF0FF33CDE9B7 +:10C7F00005304FF080730793A2F120036D461C466D +:10C8000008AE2A4603CAB24220606160154604F1B0 +:10C810000804F6D183F308884FF0FF339E466FF08B +:10C8200006031847DAE700B10047704710B5114C0E +:10C830002278B2B94FF08043D3F81824D10311D530 +:10C84000FCF738FE08B1FBF72AF80B4A0B48002129 +:10C85000FCF75AFE084A0A480121FCF755FE01235D +:10C86000237010BD074A01211160D3F81824D203A8 +:10C87000FBD5E5E7087E002027C80F00F0D50F00A4 +:10C88000F4D50F000800004070B504460D46FFF7D0 +:10C89000CDFF0C48FCF760FE94B14FF400464FF416 +:10C8A000FA7000214FF47A72E6FB0401002300F0D5 +:10C8B00083F92A460146BDE870400248FCF730BEC5 +:10C8C00070BD00BF0C7E002070B504460D46FFF71A +:10C8D000ADFF0C48FCF740FE94B14FF400464FF416 +:10C8E000FA7000214FF47A72E6FB0401002300F095 +:10C8F00063F92A460146BDE870400248FCF710BEC5 +:10C9000070BD00BF247E0020014B01221A707047C9 +:10C910003C7E002038B50C4B0C48DA6A5D6A9C6C92 +:10C92000AC2A02BF5B6BE418ED1A2A46214600F0E0 +:10C93000C5FA38B100F036F929462046BDE838403E +:10C94000FFF732B838BD00BF9873002000700F00A9 +:10C950002DE9F74F80468946A9EB0804240B02F61F +:10C96000FF76154600F0ECF8082C28BF08242303B6 +:10C97000DFF860B00193360B0DB92B4626E0B442C8 +:10C980002CBFB246A2464FF00002514640462CBF93 +:10C990002F46019FFEF7F0FF0346B8B9FA1C22F0BC +:10C9A000030249464046FEF7D9FF034670B9DBF85B +:10C9B0003030ED1BB844B9441F44CBF83070FFF75A +:10C9C00033FAA6EB0A0603460028D5D0184603B072 +:10C9D000BDE8F08F9873002010B5FFF73BFB154AB8 +:10C9E00042F20403916CCC5803F1A34303F54713BF +:10C9F00003F2D7539C4218D1D2E90C32934216D09D +:10CA0000884204D10020BDE81040FFF70DBAD21AC9 +:10CA100002F6FF7222F47F6222F00F0219441844DA +:10CA2000FFF796FF0028EDD010BD0320FCE70020A3 +:10CA3000FAE700BF9873002070B5264CE36AA52B77 +:10CA40002FD003D8012B0BD0002070BDAA2B2CD0E7 +:10CA5000AC2BF9D1FFF7C0FF28BBFFF75BFF22E04B +:10CA6000A66C656AFFF7CEFA86422AD1FFF7CAFAAA +:10CA700000222946FCF7B0FDA36A984202BF0123B9 +:10CA8000C4E90703A56100241348FFF7B1FA134B6B +:10CA9000134800221A70FFF7C7F980B944B9012082 +:10CAA000D3E7FFF799FF0124EEE7FFF733FFEAE74B +:10CAB0000120FFF7D3FA0028F1D00220C5E70320B8 +:10CAC000C3E7236BEA1AF1181844FFF741FF002867 +:10CAD000D9D1CBE798730020BC7300203C7E0020A6 +:10CAE00009C90F000A4AD2F800347BB10948002373 +:10CAF000D2F80815D940C90748BF03F5C07103F142 +:10CB0000010348BF42F82100072BF1D1704700BF55 +:10CB1000000001403546526E024B1B780BB1FFF707 +:10CB2000E1BF70473E7E0020044B002282B01A60B5 +:10CB30001B680193019B02B0704700BF00010140D8 +:10CB4000F8B5134F3A7812BB124DD5F80034E3B163 +:10CB5000D5F80445104B640904EB440449F63F46FC +:10CB6000B4428CBF002201221A70FFF7BBFFB4420F +:10CB700003D9D5F80C35DB0703D50849A008FFF722 +:10CB8000A3FE074B4FF480321A6001233B70F8BDBF +:10CB90003D7E0020000001403E7E002019CB0F00AA +:10CBA00000E100E0034BD3F800340BB1FFF79ABF6C +:10CBB000704700BF0000014053B94AB9002908BFBF +:10CBC00000281CBF4FF0FF314FF0FF3000F074B968 +:10CBD000ADF1080C6DE904CE00F006F8DDF804E0D4 +:10CBE000DDE9022304B070472DE9F047089E0446B2 +:10CBF0008846002B40F085808A42154648D9B2FA13 +:10CC000082F24AB1C2F1200701FA02F320FA07F7D3 +:10CC1000954047EA030894404FEA154E230CB8FBB1 +:10CC2000FEF71FFA85FC0EFB178843EA084307FB53 +:10CC30000CF1994209D9EB1807F1FF3080F0E3803D +:10CC4000994240F2E080023F2B445B1AA4B2B3FB4E +:10CC5000FEF00EFB103344EA034400FB0CFCA44539 +:10CC600009D92C1900F1FF3380F0CB80A44540F2A4 +:10CC7000C88002382C4440EA0740A4EB0C0400278B +:10CC80001EB1D4400023C6E900433946BDE8F08711 +:10CC9000002A53D0B2FA82F2002A40F0B680491B33 +:10CCA0004FEA154E1FFA85F80127B1FBFEFC230C55 +:10CCB0000EFB1C1143EA014308FB0CF1994207D912 +:10CCC000EB180CF1FF3002D2994200F2EC8084465E +:10CCD000591AA3B2B1FBFEF00EFB101443EA044450 +:10CCE00008FB00F8A04507D92C1900F1FF3302D248 +:10CCF000A04500F2DC801846A4EB080440EA0C4092 +:10CD0000BEE78B4208D9002E78D00027C6E9000183 +:10CD100038463946BDE8F087B3FA83F77FB98B42CE +:10CD200002D3824200F2BD80841A61EB030301202A +:10CD30009846002EA9D0C6E90048A6E7FFDEC7F155 +:10CD40002005BB4022FA05FC4CEA030C01FA07F46B +:10CD500020FA05F821FA05F34FEA1C4E48EA0404CC +:10CD6000B3FBFEF9210C0EFB19331FFA8CF841EAD4 +:10CD7000034309FB08FA9A4502FA07F200FA07F1A1 +:10CD80000BD91CEB030309F1FF3080F088809A4532 +:10CD900040F28580A9F102096344A3EB0A03A4B21F +:10CDA000B3FBFEF00EFB103344EA034400FB08F82B +:10CDB000A04508D91CEB040400F1FF336BD2A04559 +:10CDC00069D90238644440EA0940A4EB0804A0FB96 +:10CDD00002894C45C6464B4654D351D0002E69D0EB +:10CDE000B1EB0E0264EB030404FA05F522FA07F333 +:10CDF000FC401D43C6E90054002746E7374630464D +:10CE000043E7184637E707461FE7C2F1200320FA39 +:10CE100003F7954001FA02F021FA03F34FEA154EA9 +:10CE20003843010CB3FBFEF71FFA85F80EFB1733EE +:10CE300041EA034107FB08F38B4204FA02F407D9E5 +:10CE4000691807F1FF3C28D28B4226D9023F2944BA +:10CE5000CB1A81B2B3FBFEF00EFB103341EA034163 +:10CE600000FB08F38B4207D9691800F1FF3C10D290 +:10CE70008B420ED902382944C91A40EA074714E701 +:10CE80004145ABD2B8EB020E69EB0C0201381346F8 +:10CE9000A4E76046F0E7184695E76746D8E781467D +:10CEA0007BE7384645E7ACF1020C2B4410E702382B +:10CEB0002C4421E73746E8E6704700BF30B501391A +:10CEC0000024A24201D1002005E0035D01340D5D84 +:10CED000AB42F6D0581B30BD0A44914200F1FF33FB +:10CEE00000D1704710B511F8014B03F8014F914282 +:10CEF000F9D110BDF8B500BFF8BC08BC9E4670471C +:10CF0000F8B500BFF8BC08BC9E467047B857002073 +:10CF10004901B952C5EF41DE27476A5527B31CE7DF +:10CF20002D1ECB0FA00C3792BE6AB2E99B2403954D +:10CF30006593690B5EF09CFDA5C02CEEF1ECA5A1FC +:10CF4000470A9B3F814C5FD407D8A31404C609D37A +:10CF5000D75D7552957C1513FF1DFF7F645ABF7E08 +:10CF6000A91ABF7E4040922E0011922E6040823C52 +:10CF7000554BF94D504B423DFE572559F57B255BEE +:10CF80003E577F594A798A794A59775F9E656D5B2A +:10CF9000AD6B2D5B15577B5B545B527B5175965483 +:10CFA000ED076D0492041505D52700000000000070 +:10CFB0000338FDD870470D0A0050494E00574154C0 +:10CFC0004348444F47005357205245534554004C63 +:10CFD0004F434B5550004F464600000000000000F4 +:10CFE0000338FDD8704742414E4B3020494E5641E0 +:10CFF0004C49440052454C454153452042544E3122 +:10D0000020464F52204446550D0A42544E3120547A +:10D010004F20424F4F540D0A0D0A3C202020202063 +:10D0200020202020202020202020202020203E0DF5 +:10D03000003D00444655205354415254000D0A42CD +:10D040004F4F54494E472E2E2E00444953434F4EC6 +:10D050004E4543540042544E31203D205245424FEC +:10D060004F54004552524F5200535441525445447C +:10D0700000000000AC5F002044465520327631317C +:10D080002E35320A00000000000000000000000001 +:10D090000338FDD87047434845434B2053544F5203 +:10D0A000414745004E4F204E455720465700544FAC +:10D0B0004F204D414E592046494C455300464F554F +:10D0C0004E44204649524D5741524500464C41532B +:10D0D00048204845414445520020414444520020E4 +:10D0E00053495A4500204352430020564552534964 +:10D0F0004F4E0043524320544553542E2E2E00438E +:10D100005243204D49534D41544348004E4F542003 +:10D11000464C415348494E4700435243204F4B0031 +:10D1200054455354494E472E2E2E0052454D4F56CE +:10D1300045204845414445522E004649524D5741ED +:10D14000524520444946464552454E542E00464CD1 +:10D15000415348494E472E2E2E0042494E415259C6 +:10D16000204D4154434845532E00444946462041F2 +:10D170005420002056200004000004010004022076 +:10D180000403210404220405230406000407000408 +:10D190000800040900040A00040B00040C00040D3C +:10D1A00000040E00040F000410001411000412000B +:10D1B00004130004140004150004160004170004EE +:10D1C0001800041900041A00041B00041C24041D88 +:10D1D00025041E26041F2704200004210004220029 +:10D1E000042300042400042500042600042700046E +:10D1F0002800042900042A00042B00042C00042D1C +:10D2000000042E00042F000008200001FFFFFFFF94 +:10D21000FFFFFFFFFFFFFFFF000000000000000016 +:10D220000000000001000000FFFFFFFF512563FC2C +:10D23000C2CAB9F3849E17A7ADFAE6BCFFFFFFFF91 +:10D24000FFFFFFFF00000000FFFFFFFF96C298D81E +:10D250004539A1F4A033EB2D817D0377F240A4631F +:10D26000E5E6BCF847422CE1F2D1176BF551BF3728 +:10D270006840B6CBCE5E316B5733CE2B169E0F7CFB +:10D280004AEBE78E9B7F1AFEE242E34F4B60D227C8 +:10D290003E3CCE3BF6B053CCB0061D65BC869876BE +:10D2A00055BDEBB3E7933AAAD835C65A2D840F0083 +:10D2B000D9850F007F850F0051860F00982F8A4275 +:10D2C00091443771CFFBC0B5A5DBB5E95BC25639D8 +:10D2D000F111F159A4823F92D55E1CAB98AA07D8F0 +:10D2E000015B8312BE853124C37D0C55745DBE7213 +:10D2F000FEB1DE80A706DC9B74F19BC1C1699BE493 +:10D300008647BEEFC69DC10FCCA10C246F2CE92D22 +:10D31000AA84744ADCA9B05CDA88F97652513E9846 +:10D320006DC631A8C82703B0C77F59BFF30BE0C64D +:10D330004791A7D55163CA0667292914850AB727DB +:10D3400038211B2EFC6D2C4D130D385354730A6578 +:10D35000BB0A6A762EC9C281852C7292A1E8BFA24F +:10D360004B661AA8708B4BC2A3516CC719E892D1B7 +:10D37000240699D685350EF470A06A1016C1A4193A +:10D38000086C371E4C774827B5BCB034B30C1C3939 +:10D390004AAAD84E4FCA9C5BF36F2E68EE828F74F8 +:10D3A0006F63A5781478C8840802C78CFAFFBE9012 +:10D3B000EB6C50A4F7A3F9BEF27871C61B910F0075 +:10D3C00015910F00F5900F0020000000780000007C +:10D3D0000000000000000000DC5F002091920F00C0 +:10D3E0000338FDD870470000001000000400000062 +:10D3F00001000000599A0F007D9A0F008D9A0F00CE +:10D40000F99A0F009D9A0F00659A0F00699A0F0014 +:10D410006D9A0F00001000000400000001000000E1 +:10D42000099C0F00E99B0F00D99B0F00159E0F0070 +:10D43000C59D0F00AB9B0F00AF9B0F00B59B0F006E +:10D4400028004800002040000D8B0F00010000075D +:10D4500044D60F004CD60F000800000034D60F0051 +:10D4600044D60F00080000002CD60F0034D60F0061 +:10D470000800000024D60F002CD60F000800000082 +:10D480004CD60F0054D60F000800000053AB0F001D +:10D49000F7AA0F0041B00F00B3B00F00D3B00F00D8 +:10D4A0003DAA0F00FDA90F00D5AF0F00000000003E +:10D4B000011101FF0100000000000000021702FE40 +:10D4C00094000000F8D40F000000000000000000ED +:10D4D0000000000001010000010000000000000049 +:10D4E0000205000021000000000000000000000014 +:10D4F0000000000000000000011104FC0400000016 +:10D5000000000000021104FC040000000000000004 +:10D51000032104FC0410000000000000041101FFBE +:10D520000100000000000000051102FE04000000E0 +:10D5300000000000061104FC0400000000000000D0 +:10D54000071104FC0400000000000000081701FFA0 +:10D5500022000000D4D40F00091001FF01000000D8 +:10D5600070D50F0000000000000000000000000067 +:10D5700000000000011704FC98000000B0D40F0068 +:10D58000021704FCDC00000098D50F00000000002A +:10D5900000000000000000000107000098000000EB +:10D5A000B0D40F00020100000100000000000000E4 +:10D5B0000305000041000000000000000000000022 +:10D5C000000000000000000050EADA308883B89FB5 +:10D5D000604F15F30000C98E446675546172670090 +:10D5E0000338FDD870470C000C0000005802000002 +:0CD5F0000C7E0020247E002000000000C3 +:08D5FC00D5B70F0051B50F0077 +:10D604009C6200202473002045730020A462002043 +:04D614008000000092 +:0CD618000000000003000000BDB80F007F +:08D624006DB20F0000000000D0 +:08D62C00859D0F0000000000C5 +:10D63400DDA30F0000000000BDA40F0000000000E7 +:08D64400C59B0F00000000006F +:08D64C00E19C0F00000000004A +:08D65400EC9BFF7F01000000C8 +:10D65C0000000000000000000000000000000000BE +:10D66C0000000000000000000000000000000000AE +:10D67C00000000000000000000000000000000009E +:10D68C00000000000000000000000000000000008E +:10D69C00000000000000000000000000000000007E +:10D6AC00000000000000000000000000000000006E +:10D6BC000200000002000000570000002DE9F041BC +:10D6CC00214E96F82E201F2A4FF0010317D89340B5 +:10D6DC004FF0A04296F83140C2F80C35A4F1200569 +:10D6EC000122DFF8688096F828C002FA05F501449B +:10D6FC00A2404FF0A046884205D1BDE8F081203A07 +:10D70C009340124AE6E74FF0080E00271F2C94BFF7 +:10D71C00C6F80825C8F80855D6F8103523FA0CF3C6 +:10D72C001F2C4FEA470703F0010343EA070394BF9A +:10D73C00C6F80C25C8F80C55BEF1010E1F46E5D1F4 +:10D74C0000F8013BD7E7000077D10F000003005031 +:10D75C001E4A2DE9F04392F831E092F82E80012315 +:10D76C00AEF1200C03FA08F703FA0CFC03FA0EF6E0 +:10D77C00174B01444FF0A04210F8019B072449FAC3 +:10D78C0004F5B8F11F0F05F0010517D89DB1C2F8CB +:10D79C000875BEF11F0F95BFC2F80865C3F808C520 +:10D7AC00C2F80C65C3F80CC514F1FF34E7D2814202 +:10D7BC00E2D1BDE8F083C2F80C75EAE715B1C3F805 +:10D7CC000875E6E7C3F80C75E3E7000077D10F00A6 +:10D7DC0000030050114B10B593F82B401F2C88BF41 +:10D7EC00A4F120024FF001038BBF93404FF0A042F5 +:10D7FC000B4AA340C2F80C35FFF7AAFF1F2C4FF0C1 +:10D80C0001038BBF203C03FA04F403FA04F44FF039 +:10D81C00A04388BF024BC3F8084510BD77D10F0059 +:10D82C000003005013B505238DF80730164B93F801 +:10D83C002B401F2C88BFA4F120024FF001038BBF9B +:10D84C0093404FF0A042114AA340C2F80C350DF1A1 +:10D85C0007000121FFF77CFF0DF107000121FFF705 +:10D86C002DFF1F2C4FF001038BBF203C03FA04F457 +:10D87C0003FA04F44FF0A04388BF044BC3F80845E7 +:10D88C009DF8070002B010BD77D10F0000030050C7 +:10D89C0073B503238DF804300B0C8DF80530184B41 +:10D8AC0093F82B401F2C16464FF0010385BFA4F1B3 +:10D8BC00200293404FF0A042124A49BA98BFA340AD +:10D8CC00ADF806100421C2F80C3505460DEB01002D +:10D8DC00FFF73EFF31462846FFF7F0FE1F2C4FF0B6 +:10D8EC0001038BBF203C03FA04F403FA04F44FF059 +:10D8FC00A04388BF034BC3F8084502B070BD0000BD +:10D90C0077D10F00000300500B4B0222C3F8042503 +:10D91C00D3F80024002AFBD0C3F80805D3F8002460 +:10D92C00002AFBD00022C3F80425034AD2F80034A5 +:10D93C00002BFBD07047000000E001400E4BF0B50F +:10D94C000A440124401A0025914200D1F0BDC3F8CD +:10D95C000445D3F80064002EFBD0461851F8047B24 +:10D96C003760D3F80064002EFBD0C3F80455D3F80D +:10D97C000064002EFBD0E7E700E0014070472DE982 +:10D98C00F04FC7B06C4684E80F000F46044672B6E1 +:10D99C00214EDFF890A0884681464518002917DCF7 +:10D9AC00509DDFF874B01035A246B8F1000F17DCAB +:10D9BC003C44A1452CD1BFF34F8F1849184BCA6872 +:10D9CC0002F4E0621343CB60BFF34F8F00BFFDE75F +:10D9DC00681AFFF799FFC6F800A6A1F58051DDE79C +:10D9EC00B8F5807F4646A8BF4FF48076294632466C +:10D9FC0006A8FFF74DFF5046324606A9FFF79EFFDB +:10DA0C00084BCBF800363544B244A8EB0608CCE7FB +:10DA1C0019F8013B0593CCE70000014000ED00E054 +:10DA2C000400FA053546526E001001401100040046 +:10DA3C000090D003FF00FFFF0100000025720F00D3 +:04DA4C0001720F0054 +:10DA5000000000000000000033B90F0000100000BB +:04DA600000001000B2 +:020000020000FC +:020000041000EA +:0410140000700F0059 +:0410180000E00F00E5 +:04000003F00073395D +:00000001FF diff --git a/apps/fwupdate/custom.html b/apps/fwupdate/custom.html index 7a1e736e4..5cf435af5 100644 --- a/apps/fwupdate/custom.html +++ b/apps/fwupdate/custom.html @@ -3,33 +3,42 @@ -

THIS IS CURRENTLY BETA - PLEASE USE THE NORMAL FIRMWARE UPDATE - INSTRUCTIONS FOR BANGLE.JS 1 AND BANGLE.JS 2. For usage on Bangle.js 2 you'll likely need to have an updated bootloader.

+

This tool allows you to update the bootloader on Bangle.js 2 devices + from within the App Loader.

+

Firmware updates using the App Loader are only possible on Bangle.js 2. For firmware updates on Bangle.js 1 please see the Bangle.js 1 instructions

-

Your current firmware version is unknown

+ -

Firmware updates via this tool work differently to the NRF Connect method mentioned on - the Bangle.js page. Firmware - is uploaded to a file on the Bangle. Once complete the Bangle reboots and the bootloader copies - the new firmware into internal Storage.

+

 
@@ -38,7 +47,6 @@
     
 
     
diff --git a/apps/fwupdate/metadata.json b/apps/fwupdate/metadata.json
index c44a0115a..8f33e493a 100644
--- a/apps/fwupdate/metadata.json
+++ b/apps/fwupdate/metadata.json
@@ -1,8 +1,8 @@
 {
   "id": "fwupdate",
   "name": "Firmware Update",
-  "version": "0.03",
-  "description": "[BETA] Uploads new Espruino firmwares to Bangle.js 2. For now, please use the instructions under https://www.espruino.com/Bangle.js2#firmware-updates",
+  "version": "0.04",
+  "description": "Uploads new Espruino firmwares to Bangle.js 2",
   "icon": "app.png",
   "type": "RAM",
   "tags": "tools,system",
diff --git a/apps/health/ChangeLog b/apps/health/ChangeLog
index c65cc3ab4..a693b2a83 100644
--- a/apps/health/ChangeLog
+++ b/apps/health/ChangeLog
@@ -8,3 +8,4 @@
 0.07: Added coloured bar charts
 0.08: Suppress bleed through of E.showMenu's when displaying bar charts
 0.09: Fix file naming so months are 1-based (not 0) (fix #1119)
+0.10: Adds additional 3 minute setting for HRM
diff --git a/apps/health/app.js b/apps/health/app.js
index 08d6ead17..7a55eec27 100644
--- a/apps/health/app.js
+++ b/apps/health/app.js
@@ -28,8 +28,8 @@ function menuSettings() {
     "< Back":()=>menuMain(),
     "Heart Rt":{
       value : 0|s.hrm,
-      min : 0, max : 2,
-      format : v=>["Off","10 mins","Always"][v],
+      min : 0, max : 3,
+      format : v=>["Off","3 mins","10 mins","Always"][v],
       onchange : v => { s.hrm=v;setSettings(s); }
     }
   });
diff --git a/apps/health/boot.js b/apps/health/boot.js
index c72e62b41..7b9aa51aa 100644
--- a/apps/health/boot.js
+++ b/apps/health/boot.js
@@ -1,18 +1,28 @@
 (function(){
-   var settings = require("Storage").readJSON("health.json",1)||{};
-   var hrm = 0|settings.hrm;
-   if (hrm==1) {
-     function onHealth() {
-       Bangle.setHRMPower(1, "health");
-       setTimeout(()=>Bangle.setHRMPower(0, "health"),2*60000); // give it 2 minutes
+  var settings = require("Storage").readJSON("health.json",1)||{};
+  var hrm = 0|settings.hrm;
+  if (hrm == 1 || hrm == 2) {
+   function onHealth() {
+     Bangle.setHRMPower(1, "health");
+     setTimeout(()=>Bangle.setHRMPower(0, "health"),hrm*60000); // give it 1 minute detection time for 3 min setting and 2 minutes for 10 min setting
+     if (hrm == 1){
+       for (var i = 1; i <= 2; i++){
+         setTimeout(()=>{
+           Bangle.setHRMPower(1, "health");
+           setTimeout(()=>{
+             Bangle.setHRMPower(0, "health");
+           }, (i * 200000) + 60000);
+         }, (i * 200000));
+       }
      }
-     Bangle.on("health", onHealth);
-     Bangle.on('HRM', h => {
-       if (h.confidence>80) Bangle.setHRMPower(0, "health");
-     });
-     if (Bangle.getHealthStatus().bpmConfidence) return;
-     onHealth();
-   } else Bangle.setHRMPower(hrm!=0, "health");
+   }
+   Bangle.on("health", onHealth);
+   Bangle.on('HRM', h => {
+     if (h.confidence>80) Bangle.setHRMPower(0, "health");
+   });
+   if (Bangle.getHealthStatus().bpmConfidence) return;
+   onHealth();
+  } else Bangle.setHRMPower(hrm!=0, "health");
 })();
 
 Bangle.on("health", health => {
diff --git a/apps/health/interface.html b/apps/health/interface.html
index f04857926..0791acd24 100644
--- a/apps/health/interface.html
+++ b/apps/health/interface.html
@@ -51,7 +51,7 @@ function saveCSV(data, date, title) {
 }
 
 function downloadHealth(filename, callback) {
-  Util.showModal("Downloading Track...");
+  Util.showModal("Downloading Health info...");
   Util.readStorage(filename, data => {
     Util.hideModal();
     callback(data);
diff --git a/apps/health/metadata.json b/apps/health/metadata.json
index b96087e1b..da9d764ea 100644
--- a/apps/health/metadata.json
+++ b/apps/health/metadata.json
@@ -1,7 +1,7 @@
 {
   "id": "health",
   "name": "Health Tracking",
-  "version": "0.09",
+  "version": "0.10",
   "description": "Logs health data and provides an app to view it (requires firmware 2v10.100 or later)",
   "icon": "app.png",
   "tags": "tool,system,health",
diff --git a/apps/hrmaccevents/ChangeLog b/apps/hrmaccevents/ChangeLog
new file mode 100644
index 000000000..5560f00bc
--- /dev/null
+++ b/apps/hrmaccevents/ChangeLog
@@ -0,0 +1 @@
+0.01: New App!
diff --git a/apps/hrmaccevents/app.png b/apps/hrmaccevents/app.png
new file mode 100644
index 000000000..337b3cdc8
Binary files /dev/null and b/apps/hrmaccevents/app.png differ
diff --git a/apps/hrmaccevents/custom.html b/apps/hrmaccevents/custom.html
new file mode 100644
index 000000000..c0098eb12
--- /dev/null
+++ b/apps/hrmaccevents/custom.html
@@ -0,0 +1,190 @@
+
+ 
+  Bangle.js Accelerometer streaming
+ 
+ 
+
+
+
+
+
+

+ + + diff --git a/apps/hrmaccevents/metadata.json b/apps/hrmaccevents/metadata.json new file mode 100644 index 000000000..de59dceac --- /dev/null +++ b/apps/hrmaccevents/metadata.json @@ -0,0 +1,14 @@ +{ + "id": "hrmaccevents", + "name": "HRM Accelerometer event recorder", + "shortName": "HRM ACC recorder", + "version": "0.01", + "type": "ram", + "description": "Record HRM and accelerometer events in high resolution to CSV files in your browser", + "icon": "app.png", + "tags": "debug", + "supports": ["BANGLEJS","BANGLEJS2"], + "custom": "custom.html", + "customConnect": true, + "storage": [ ] +} diff --git a/apps/impwclock/ChangeLog b/apps/impwclock/ChangeLog index 7bc119426..6555fcc8f 100644 --- a/apps/impwclock/ChangeLog +++ b/apps/impwclock/ChangeLog @@ -2,3 +2,4 @@ 0.02: Stopped watchface from flashing every interval 0.03: Move to Bangle.setUI to launcher support 0.04: Tweaks for compatibility with BangleJS2 +0.05: Time-word now readable on Bangle.js 2 diff --git a/apps/impwclock/clock-impword.js b/apps/impwclock/clock-impword.js index 8bb5da6ba..c42dbda44 100644 --- a/apps/impwclock/clock-impword.js +++ b/apps/impwclock/clock-impword.js @@ -46,7 +46,7 @@ const dy = big ? 22 : 16; const fontSize = big ? 3 : 2; // "6x8" const passivColor = 0x3186 /*grey*/ ; const activeColorNight = 0xF800 /*red*/ ; -const activeColorDay = 0xFFFF /* white */; +const activeColorDay = g.theme.fg; var hidxPrev; var showDigitalTime = false; diff --git a/apps/impwclock/metadata.json b/apps/impwclock/metadata.json index 6bf5183f4..120fbe795 100644 --- a/apps/impwclock/metadata.json +++ b/apps/impwclock/metadata.json @@ -1,7 +1,7 @@ { "id": "impwclock", "name": "Imprecise Word Clock", - "version": "0.04", + "version": "0.05", "description": "Imprecise word clock for vacations, weekends, and those who never need accurate time.", "icon": "clock-impword.png", "type": "clock", diff --git a/apps/lapcounter/ChangeLog b/apps/lapcounter/ChangeLog index 146ff1b05..2893d3193 100644 --- a/apps/lapcounter/ChangeLog +++ b/apps/lapcounter/ChangeLog @@ -1,2 +1,3 @@ 0.01: first release 0.02: Themeable app icon +0.03: Behave better on Bangle.js 1 diff --git a/apps/lapcounter/app.js b/apps/lapcounter/app.js index 215f6140a..f2f3873d7 100644 --- a/apps/lapcounter/app.js +++ b/apps/lapcounter/app.js @@ -5,7 +5,7 @@ let tStart; let tNow; let counter=-1; -const icon = require("heatshrink").decompress(atob("mEwwkBiIA/AH4A/AAkQgEBAREAC6oABdZQXkI6wuKC5iPUFxoXIOpoX/C6QFCC6IsCC6ZEDC/4XcPooXOFgoXQIgwX/C7IUFC5wsIC5ouCC6hcJC5h1DF9YwBChCPOAH4A/AH4Ap")); +const icon = require("heatshrink").decompress(atob("mEwwI0xg+evPsAon+ApX8Aon4AonwAod78AFDv4FWvoFE/IFDz4FXvIFD3wFE/wFW7wFDh5xBAoUfAok/Aol/BZUXAogA6A=")); function timeToText(t) { // Courtesy of stopwatch app let hrs = Math.floor(t/3600000); @@ -50,4 +50,5 @@ g.drawImage(icon,w/2-24,h/2-24); g.setFontAlign(0,0); require("Font8x12").add(Graphics); g.setFont("8x12"); -g.drawString("Click button to count.", w/2, h/2+22); +g.drawString("Click button 1 to count.", w/2, h/2+22); + diff --git a/apps/lapcounter/metadata.json b/apps/lapcounter/metadata.json index dcc3440ec..3210c6a49 100644 --- a/apps/lapcounter/metadata.json +++ b/apps/lapcounter/metadata.json @@ -1,7 +1,7 @@ { "id": "lapcounter", "name": "Lap Counter", - "version": "0.02", + "version": "0.03", "description": "Click button to count laps. Shows count and total time snapshot (like a stopwatch, but laid back).", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], diff --git a/apps/notanalog/ChangeLog b/apps/notanalog/ChangeLog index aedbeb684..574d46609 100644 --- a/apps/notanalog/ChangeLog +++ b/apps/notanalog/ChangeLog @@ -1 +1,3 @@ 0.01: Launch app. +0.02: 12k steps are 360 degrees - improves readability of steps. +0.03: Battery improvements through sleep (no minute updates) and partial updates of drawing. \ No newline at end of file diff --git a/apps/notanalog/README.md b/apps/notanalog/README.md index 22097f0fc..2928fd959 100644 --- a/apps/notanalog/README.md +++ b/apps/notanalog/README.md @@ -1,20 +1,21 @@ -# NotAnalog +# Not Analog An analog watch face for people (like me) that can not read analog watch faces. It looks like an analog clock, but its not! It shows the time digital - check the 4 numbers on the watch face ;) -The red hand shows the number of steps (0 = 0°, 2.5k = 90°, 5k = 180°, ...) and the -black one the battery level (100% = 0°, 75% = 270°, 50% = 180°, ...). +The red hand shows the number of steps (12k steps = 360 degrees) and the +black one the battery level (100% = 360 degrees). The selected theme is also respected. Note that this watch face is in fullscreen mode, but widgets are still loaded in background. ## Other features - Set a timer - simply touch top (+5min.) or bottom (-5 min.). - If the weather is available through the weather app, the outside temp. will be shown. -- If the battery is charged, the icons will change. +- Sleep modus at midnight to save more battery (no minute updates). +- Icons for charging and GPS. - If you have done more than 10k steps, the red hand and icon will turn green. - Shows current lock status of your bangle va a colored dot in the middle. -- Sows symbol if GPS is on. + ## Screenshots ![](screenshot_1.png) diff --git a/apps/notanalog/metadata.json b/apps/notanalog/metadata.json index a2ce9260d..5efb6bccf 100644 --- a/apps/notanalog/metadata.json +++ b/apps/notanalog/metadata.json @@ -3,7 +3,7 @@ "name": "Not Analog", "shortName":"Not Analog", "icon": "notanalog.png", - "version":"0.1", + "version":"0.03", "readme": "README.md", "supports": ["BANGLEJS2"], "description": "An analog watch face for people that can not read analog watch faces.", diff --git a/apps/notanalog/notanalog.app.js b/apps/notanalog/notanalog.app.js index ad8adfe83..cea8072b8 100644 --- a/apps/notanalog/notanalog.app.js +++ b/apps/notanalog/notanalog.app.js @@ -28,7 +28,8 @@ var state = { maxSteps: 10000, bat: 0, has_weather: false, - temp: "-" + temp: "-", + sleep: false, } var chargeImg = { @@ -55,6 +56,12 @@ var gpsImg = { buffer : E.toArrayBuffer(atob("AAAMAAAAD4AAAAHAAAAA4AAADjABAA8YAYADmAPAAcwD4DzMB/B8zAf4fAAH/HwAB/74AAf/wAAH/4AAB//AAAP/4AAD//AAA//4AAH//AAA//4AAH//AAA//4ABH/4AAYP4AAHgAAAB/AAAA/4AAAP+AAAD/gAAP//gAD//4AA=")) }; +var sleepImg = { + width : 128, height : 128, bpp : 1, + transparent : 0, + buffer : require("heatshrink").decompress(atob("ABk//+AB5l///AB5wfDh4kIF4s/8AgIj4ED//wB5E+AYUB//8B5F8AYUD+F+B5H4AYUH8E/Bw8BHIcHwEfMA4PEh4RBQo8DNIYPBIIIPGDAkeEwJGDAAaZEB4MAOAisB+COEngCBOAn///4NAgPCMAgfCZ4gPCaIpWBd4l4QQZtFD4gPCgYPEQw3wRo41FgHxfw5tEB4sHfg7DC8IPDFQb8DB4XgB4ZDDWosD4DNCbAbsEB4zRDB5bRDfghKDB4bRCRwwPBuAFCbISOCgP/EYMPK4kPDgKOCgbiBDIJLDEoIYBRwQPD//DD4hQBbgPgF4QCB84PDBgICCDgJTBEQP/B4QFCwAIDKYIRB/84bQX/x+AD4YPCwF+nguC+B9FMYJuBngPBIgKmCeQoPEg5dBB4ryBB4kPPoMfdohRCB4McSYPAg5dBeQoPCjxOBCIIPBcQYUBL4N4j0B/hQBAATPBV4RnB/EegYFB//AbYYPCgfh+EeZgJNDAYYWBCQUedgN/NoUD/xhDEwUOj67BBQd/IAIFEh8+gZ3CNQMfSQkMBQN8g/wMATKBCQIAEh/4IAMPdoQlCB4vwn7sC/5OBSIQPE8F+KoRoBfIIPFPwP8cASyBQoIPG4JABJQUHAoJwEBAODIAUBAIIlBOAg/BgfgcAMDBYN+A4IPFC4I+BB4U/wKAFh8PwJ5BB4SFBB40fFANggPAg5nBSAsPzwwBDIRGB+F8L4v+NAIZCh8B+E8B4v8RAN4AwMOgH4jwPEY4M+gEwB4d8UA34E4sAn0PA4pHGgEeWApHBfA8HB4vgQ4oPBw4PF8IPGbALQEgfB8IXF4/DB4vD8YHG4LgEEwPDA4oPIA4w3BA4pWBF4poGdAJOEAAQPFQwyoDB4q2GB6VwB5twvAFDhwPIvAPFhwPNjwPTgaSDBwgPBj//wH//6qCnAPI4IPEvgPY4APEngPGjxPOL5KvER4gPFV5IPKZ4gPEZ4oPJd5QPF+APEg+AB5kHB5+HB40B8APFwfBVgIPCgeB8K0CB4fDB4kH4YXCLQfDB4oHBB43B8ZABB4UB4/DKgYPCCwRPDHAIPEKwgPDh+HB434B4yIDQwbGCB4ceB434ngPFnzIDewc+gEwB4MEgF8j4PFA4V4B4MOE4MeB4s8h+AB4QsBG4YADI4PA+APCgfwvgPFj8D8FwB4L2B8BnCAAcPwKQBL4UPEoIPFFwP8B4cfCwQPGvwPDv42BB4oHBn+AB4MB/gXBB4sB/Ef8BPC/B2BB4sADIP8B4M/8CeGAAN+gP/4fB//AWwIAGn5LB/4ABEwIPHj/Aj4OB/BGBB46ZBgYPBKAJ+GOAQZBj4sBEoIPHgP+Aod/Nw4KCDQQUFKAw6Ch5eIKAX/FYP/JxArCPwQSCABM/BwI+KGAYuLEAYeGA=")) +}; + /* * Based on the great multi clock from https://github.com/jeffmer/BangleApps/ @@ -83,17 +90,18 @@ Graphics.prototype.setNormalFont = function(scale) { function getSteps() { - var steps = 0; - let health; - try { - health = require("health"); + try{ + if (WIDGETS.wpedom !== undefined) { + return WIDGETS.wpedom.getSteps(); + } else if (WIDGETS.activepedom !== undefined) { + return WIDGETS.activepedom.getSteps(); + } } catch(ex) { - return steps; + // In case we failed, we can only show 0 steps. } - health.readDay(new Date(), h=>steps+=h.steps); - return steps; -} + return 0; + } function drawBackground() { @@ -169,7 +177,12 @@ function drawData() { } // Default are the steps - drawDataHand(parseInt(state.steps*360/state.maxSteps)); + drawDataHand(parseInt(state.steps*360/12000)); +} + +function drawTextCleared(s, x, y){ + g.clearRect(x-15, y-22, x+15, y+15); + g.drawString(s, x, y); } @@ -178,36 +191,33 @@ function drawTime(){ g.setFontAlign(0,0,0); g.setColor(g.theme.fg); - var currentDate = new Date(); var posX = 14; var posY = 14; // Hour - var h = currentDate.getHours(); + var h = state.currentDate.getHours(); var h1 = parseInt(h / 10); var h2 = h < 10 ? h : h - h1*10; - g.drawString(h1, cx, posY+8); - g.drawString(h2, W-posX, cy+5); + drawTextCleared(h1, cx, posY+8); + drawTextCleared(h2, W-posX, cy+5); // Minutes - var m = currentDate.getMinutes(); + var m = state.currentDate.getMinutes(); var m1 = parseInt(m / 10); var m2 = m < 10 ? m : m - m1*10; - g.drawString(m2, cx, H-posY); - g.drawString(m1, posX-1, cy+5); + drawTextCleared(m2, cx, H-posY); + drawTextCleared(m1, posX-1, cy+5); } function drawDate(){ - var currentDate = new Date(); - // Date g.setFontAlign(-1,0,0); g.setNormalFont(); g.setColor(g.theme.fg); - var dayStr = locale.dow(currentDate, true).toUpperCase(); + var dayStr = locale.dow(state.currentDate, true).toUpperCase(); g.drawString(dayStr, cx/2-15, cy/2-5); - g.drawString(currentDate.getDate(), cx/2-15, cy/2+17); + g.drawString(state.currentDate.getDate(), cx/2-15, cy/2+17); } @@ -222,22 +232,36 @@ function drawLock(){ function handleState(fastUpdate){ - // Set theme color + state.currentDate = new Date(); + + /* + * Sleep modus + */ + var minutes = state.currentDate.getMinutes(); + var hours = state.currentDate.getHours(); + if(!isAlarmEnabled() && fastUpdate && hours == 00 && minutes == 01){ + state.sleep = true; + return; + } + + // Set steps + state.steps = getSteps(); + + // Color based on state state.color = isAlarmEnabled() ? "#FF6A00" : state.steps > state.maxSteps ? "#00ff00" : "#ff0000"; - if(fastUpdate){ + /* + * 5 Minute updates + */ + if(minutes % 5 == 0 && fastUpdate){ return; } // Set battery state.bat = E.getBattery(); - // Set steps - state.steps = getSteps(); - state.maxSteps = 10000; - // Set weather state.has_weather = true; try { @@ -251,7 +275,16 @@ function handleState(fastUpdate){ } catch(ex) { state.has_weather = false; } +} + +function drawSleep(){ + g.reset(); + g.clearRect(0, 0, g.getWidth(), g.getHeight()); + drawBackground(); + + g.setColor(1,1,1); + g.drawImage(sleepImg, cx - sleepImg.width/2, cy- sleepImg.height/2); } @@ -260,6 +293,13 @@ function draw(fastUpdate){ handleState(fastUpdate); handleAlarm(); + if(state.sleep){ + drawSleep(); + // We don't queue draw again - so its sleeping until + // the user presses the btn again. + return; + } + // Clear watch face if(fastUpdate){ var innerRect = 20; @@ -279,8 +319,8 @@ function draw(fastUpdate){ drawDate(); drawLock(); drawState(); - drawData(); drawTime(); + drawData(); // Queue draw in one minute queueDraw(); @@ -292,7 +332,7 @@ function draw(fastUpdate){ */ Bangle.on('lcdPower',on=>{ if (on) { - draw(false); + draw(true); } else { // stop draw timer if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; @@ -300,11 +340,16 @@ Bangle.on('lcdPower',on=>{ }); Bangle.on('charging',function(charging) { - draw(false); + draw(true); }); Bangle.on('lock', function(isLocked) { - drawLock(); + if(state.sleep){ + state.sleep=false; + draw(false); + } else { + drawLock(); + } }); Bangle.on('touch', function(btn, e){ @@ -335,7 +380,7 @@ function queueDraw() { if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = setTimeout(function() { drawTimeout = undefined; - draw(false); + draw(true); }, 60000 - (Date.now() % 60000)); } diff --git a/apps/notanalog/notanalog.icon.js b/apps/notanalog/notanalog.icon.js index 390a574ac..2af96aef9 100644 --- a/apps/notanalog/notanalog.icon.js +++ b/apps/notanalog/notanalog.icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwkAxAA/ADWP/AWV/4XVxAXX5/5Iif/xHvF6QXDF6YADF5GHv4lBAAP3hBfOw4VDAAd4F5gWIAAIxFF4wREAxB6EGAZbC5+PAAYZD+woFIozoIJI4uFFogxEIQPwEZLdKaoYJIFxBiEIxAuKEwZIGFxeM/ADBGA6MJFgYPDSIouKBYovHLxOPBQZgHL4YNCFxAXB+4XFEYgpEHIpAGKYoMBFw6IHF4oYDNA3//yPLC4QAHF4olFTo4KJX46SEF6AHCz7FLF5OJz70HR5IADxOYBAy/LF8nwAwowGF46OBwBOLF5AXB5AvTB4UIC4wvNH48PC4JfMLwxPCGAovGHw4JD/AvKC5JIBBRAkDXooACwwLBMQyMDRowwGGIwIC4A7JPQZkDAoYVKAAOACIYAE/BFJA=")) \ No newline at end of file +require("heatshrink").decompress(atob("mEwwkE/4AM+cikMRkU/CZoWDkMAgMQgESDB4WBgMSkcykMQDB8xgMjAwcyiETFxoPHD4IwMBxAgBG4gLFCYMgHxExgQXI+USEoMvBhBIJ+URmQMJERQKBiI8BmQZHKRJTBgETmURC48xC5PxgERaBPxga9KgDnJ+KQJKYJFIQoQXKOhAvK+cRgBeBC5ZfF+QVBAAacKBQgWGAALNIX4iJCAA0Bd5kwCw4ABWw3ygJrC+YWJAAJeGRwboBIQhMFj5GFLwcgCAoeFW4kxIwf/IAoXGgARCmQuEUgwXHiczCwMCFwfwC5sBfIMRYwilGC5MSkaTEagwXImbbGC54WGRwwXIbIwXh+YXVh6YHC453GN4IwFO5AXGJAIwFgQXHHwwwHgYXH+AXGGAxnBAAyfHGAwdBAAyfHCQaOKAAMgGBEhOxRIKGYoAJC5YWKVJClLbRjsJAAvyC48vC5v/mJ0RYgyiCiU/CyAASA==")) \ No newline at end of file diff --git a/apps/notanalog/notanalog.png b/apps/notanalog/notanalog.png index f27d79729..117f19506 100644 Binary files a/apps/notanalog/notanalog.png and b/apps/notanalog/notanalog.png differ diff --git a/apps/run/ChangeLog b/apps/run/ChangeLog index 0df910367..811e3afba 100644 --- a/apps/run/ChangeLog +++ b/apps/run/ChangeLog @@ -2,3 +2,4 @@ 0.02: Set pace format to mm:ss, time format to h:mm:ss, added settings to opt out of GPS and HRM 0.03: Fixed distance calculation, tested against Garmin Etrex, Amazfit GTS 2 +0.04: Use the exstats module, and make what is displayed configurable diff --git a/apps/run/README.md b/apps/run/README.md index c094d4873..10f6bafdb 100644 --- a/apps/run/README.md +++ b/apps/run/README.md @@ -28,7 +28,24 @@ so if you have no GPS lock you just need to wait. However you can just install the `Recorder` app, turn recording on in that, and then start the `Run` app. +## Settings + +Under `Settings` -> `App` -> `Run` you can change settings for this app. + +* `Pace` is the distance that pace should be shown over - 1km, 1 mile, 1/2 Marathon or 1 Marathon +* `Box 1/2/3/4/5/6` are what should be shown in each of the 6 boxes on the display. From the top left, down. + If you set it to `-` nothing will be displayed, so you can display only 4 boxes of information + if you wish by setting the last 2 boxes to `-`. + ## TODO * Allow this app to trigger the `Recorder` app on and off directly. * Keep a log of each run's stats (distance/steps/etc) + +## Development + +This app uses the [`exstats` module](/modules/exstats.js). When uploaded via the +app loader, the module is automatically included in the app's source. However +when developing via the IDE the module won't get pulled in by default. + +There are some options to fix this easily - please check out the [modules README.md file](/modules/README.md) diff --git a/apps/run/app.js b/apps/run/app.js index a92bbe387..9e313ea2a 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -1,68 +1,37 @@ +var ExStats = require("exstats"); var B2 = process.env.HWVERSION==2; var Layout = require("Layout"); var locale = require("locale"); var fontHeading = "6x8:2"; var fontValue = B2 ? "6x15:2" : "6x8:3"; var headingCol = "#888"; -var running = false; var fixCount = 0; -var startTime; -var startSteps; -// This & previous GPS readings -var lastGPS, thisGPS; -var distance = 0; ///< distance in meters -var startSteps = Bangle.getStepCount(); ///< number of steps when we started -var lastStepCount = startSteps; // last time 'step' was called -var stepHistory = new Uint8Array(60); // steps each second for the last minute (0 = current minute) g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); // --------------------------- - -function formatTime(ms) { - let hrs = Math.floor(ms/3600000).toString(); - let mins = (Math.floor(ms/60000)%60).toString(); - let secs = (Math.floor(ms/1000)%60).toString(); - - if (hrs === '0') - return mins.padStart(2,0)+":"+secs.padStart(2,0); - else - return hrs+":"+mins.padStart(2,0)+":"+secs.padStart(2,0); // dont pad hours -} - -// Format speed in meters/second -function formatPace(speed) { - if (speed < 0.1667) { - return `__:__`; - } - const pace = Math.round(1000 / speed); // seconds for 1km - const min = Math.floor(pace / 60); // minutes for 1km - const sec = pace % 60; - return ('0' + min).substr(-2) + `:` + ('0' + sec).substr(-2); -} - +let settings = Object.assign({ + B1 : "dist", + B2 : "time", + B3 : "pacea", + B4 : "bpm", + B5 : "step", + B6 : "caden", + paceLength : 1000 +}, require("Storage").readJSON("run.json", 1) || {}); +var statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,settings.B6].filter(s=>s!=""); +var exs = ExStats.getStats(statIDs, settings); // --------------------------- -function clearState() { - distance = 0; - startSteps = Bangle.getStepCount(); - stepHistory.fill(0); - layout.dist.label=locale.distance(distance); - layout.time.label="00:00"; - layout.pace.label=formatPace(0); - layout.hrm.label="--"; - layout.steps.label=0; - layout.cadence.label= "0"; - layout.status.bgCol = "#f00"; -} - +// Called to start/stop running function onStartStop() { - running = !running; + var running = !exs.state.active; if (running) { - clearState(); - startTime = Date.now(); + exs.start(); + } else { + exs.stop(); } layout.button.label = running ? "STOP" : "START"; layout.status.label = running ? "RUN" : "STOP"; @@ -72,107 +41,44 @@ function onStartStop() { layout.render(); } +var lc = []; +// Load stats in pair by pair +for (var i=0;ilayout[e.id].label = e.getString()); + sb.on('changed', e=>layout[e.id].label = e.getString()); +} +// At the bottom put time/GPS state/etc +lc.push({ type:"h", filly:1, c:[ + {type:"txt", font:fontHeading, label:"GPS", id:"gps", fillx:1, bgCol:"#f00" }, + {type:"txt", font:fontHeading, label:"00:00", id:"clock", fillx:1, bgCol:g.theme.fg, col:g.theme.bg }, + {type:"txt", font:fontHeading, label:"STOP", id:"status", fillx:1 } +]}); +// Now calculate the layout var layout = new Layout( { - type:"v", c: [ - { type:"h", filly:1, c:[ - {type:"txt", font:fontHeading, label:"DIST", fillx:1, col:headingCol }, - {type:"txt", font:fontHeading, label:"TIME", fillx:1, col:headingCol } - ]}, { type:"h", filly:1, c:[ - {type:"txt", font:fontValue, label:"0.00", id:"dist", fillx:1 }, - {type:"txt", font:fontValue, label:"00:00", id:"time", fillx:1 } - ]}, { type:"h", filly:1, c:[ - {type:"txt", font:fontHeading, label:"PACE", fillx:1, col:headingCol }, - {type:"txt", font:fontHeading, label:"HEART", fillx:1, col:headingCol } - ]}, { type:"h", filly:1, c:[ - {type:"txt", font:fontValue, label:`__'__"`, id:"pace", fillx:1 }, - {type:"txt", font:fontValue, label:"--", id:"hrm", fillx:1 } - ]}, { type:"h", filly:1, c:[ - {type:"txt", font:fontHeading, label:"STEPS", fillx:1, col:headingCol }, - {type:"txt", font:fontHeading, label:"CADENCE", fillx:1, col:headingCol } - ]}, { type:"h", filly:1, c:[ - {type:"txt", font:fontValue, label:"0", id:"steps", fillx:1 }, - {type:"txt", font:fontValue, label:"0", id:"cadence", fillx:1 } - ]}, { type:"h", filly:1, c:[ - {type:"txt", font:fontHeading, label:"GPS", id:"gps", fillx:1, bgCol:"#f00" }, - {type:"txt", font:fontHeading, label:"00:00", id:"clock", fillx:1, bgCol:g.theme.fg, col:g.theme.bg }, - {type:"txt", font:fontHeading, label:"STOP", id:"status", fillx:1 } - ]}, - - ] + type:"v", c: lc },{lazy:true, btns:[{ label:"START", cb: onStartStop, id:"button"}]}); -clearState(); +delete lc; layout.render(); -function onTimer() { - layout.clock.label = locale.time(new Date(),1); - if (!running) { - layout.render(); - return; - } - // called once a second - var duration = Date.now() - startTime; // in ms - // set cadence based on steps over last minute - var stepsInMinute = E.sum(stepHistory); - var cadence = 60000 * stepsInMinute / Math.min(duration,60000); - // update layout - layout.time.label = formatTime(duration); - layout.steps.label = Bangle.getStepCount()-startSteps; - layout.cadence.label = Math.round(cadence); - layout.render(); - // move step history onwards - stepHistory.set(stepHistory,1); - stepHistory[0]=0; -} - -function radians(a) { - return a*Math.PI/180; -} - -// distance between 2 lat and lons, in meters, Mean Earth Radius = 6371km -// https://www.movable-type.co.uk/scripts/latlong.html -function calcDistance(a,b) { - var x = radians(a.lon-b.lon) * Math.cos(radians((a.lat+b.lat)/2)); - var y = radians(b.lat-a.lat); - return Math.round(Math.sqrt(x*x + y*y) * 6371000); -} - +// Handle GPS state change for icon Bangle.on("GPS", function(fix) { layout.gps.bgCol = fix.fix ? "#0f0" : "#f00"; - if (!fix.fix) { return; } // only process actual fixes + if (!fix.fix) return; // only process actual fixes if (fixCount++ == 0) { Bangle.buzz(); // first fix, does not need to respect quiet mode - lastGPS = fix; // initialise on first fix - } - - thisGPS = fix; - - if (running) { - var d = calcDistance(lastGPS, thisGPS); - distance += d; - layout.dist.label=locale.distance(distance); - var duration = Date.now() - startTime; // in ms - var speed = distance * 1000 / duration; // meters/sec - layout.pace.label = formatPace(speed); - lastGPS = fix; } }); -Bangle.on("HRM", function(h) { - layout.hrm.label = h.bpm; -}); -Bangle.on("step", function(steps) { - if (running) { - layout.steps.label = steps-Bangle.getStepCount(); - stepHistory[0] += steps-lastStepCount; - } - lastStepCount = steps; -}); - -let settings = require("Storage").readJSON('run.json',1)||{"use_gps":true,"use_hrm":true}; - -// We always call ourselves once a second, if only to update the time -setInterval(onTimer, 1000); - -/* Turn GPS and HRM on right at the start to ensure -we get the highest chance of a lock. */ -if (settings.use_hrm) Bangle.setHRMPower(true,"app"); -if (settings.use_gps) Bangle.setGPSPower(true,"app"); +// We always call ourselves once a second to update +setInterval(function() { + layout.clock.label = locale.time(new Date(),1); + layout.render(); +}, 1000); diff --git a/apps/run/metadata.json b/apps/run/metadata.json index 4d5e85778..2fd4497f6 100644 --- a/apps/run/metadata.json +++ b/apps/run/metadata.json @@ -1,6 +1,6 @@ { "id": "run", "name": "Run", - "version":"0.03", + "version":"0.04", "description": "Displays distance, time, steps, cadence, pace and more for runners.", "icon": "app.png", "tags": "run,running,fitness,outdoors,gps", diff --git a/apps/run/settings.js b/apps/run/settings.js index 882b15c71..91a8b4333 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -1,44 +1,50 @@ (function(back) { const SETTINGS_FILE = "run.json"; - - // initialize with default settings... - let s = { - 'use_gps': true, - 'use_hrm': true - } + var ExStats = require("exstats"); + var statsList = ExStats.getList(); + statsList.unshift({name:"-",id:""}); // add blank menu item + var statsIDs = statsList.map(s=>s.id); // ...and overwrite them with any saved values // This way saved values are preserved if a new version adds more settings const storage = require('Storage') - let settings = storage.readJSON(SETTINGS_FILE, 1) || {} - const saved = settings || {} - for (const key in saved) { - s[key] = saved[key] - } - - function save() { - settings = s + let settings = Object.assign({ + B1 : "dist", + B2 : "time", + B3 : "pacea", + B4 : "bpm", + B5 : "step", + B6 : "caden", + paceLength : 1000 + }, storage.readJSON(SETTINGS_FILE, 1) || {}); + function saveSettings() { storage.write(SETTINGS_FILE, settings) } - E.showMenu({ - '': { 'title': 'Run' }, - '< Back': back, - 'Use GPS': { - value: s.use_gps, - format: () => (s.use_gps ? 'Yes' : 'No'), - onchange: () => { - s.use_gps = !s.use_gps; - save(); - }, - }, - 'Use HRM': { - value: s.use_hrm, - format: () => (s.use_hrm ? 'Yes' : 'No'), - onchange: () => { - s.use_hrm = !s.use_hrm; - save(); + function getBoxChooser(boxID) { + return { + min :0, max: statsIDs.length-1, + value: Math.max(statsIDs.indexOf(settings[boxID]),0), + format: v => statsList[v].name, + onchange: v => { + settings[boxID] = statsIDs[v]; + saveSettings(); }, } - }) + } + + var menu = { + '': { 'title': 'Run' }, + '< Back': back + }; + ExStats.appendMenuItems(menu, settings, saveSettings); + Object.assign(menu,{ + 'Box 1': getBoxChooser("B1"), + 'Box 2': getBoxChooser("B2"), + 'Box 3': getBoxChooser("B3"), + 'Box 4': getBoxChooser("B4"), + 'Box 5': getBoxChooser("B5"), + 'Box 6': getBoxChooser("B6"), + }); + E.showMenu(menu); }) diff --git a/apps/sensible/ChangeLog b/apps/sensible/ChangeLog index 33e44b70c..0699954d7 100644 --- a/apps/sensible/ChangeLog +++ b/apps/sensible/ChangeLog @@ -2,4 +2,5 @@ 0.02: Corrected variable initialisation 0.03: Advertise app name, added screenshots 0.04: Advertise bar, GPS, HRM and mag services -0.05: Refactored for efficiency, corrected sensor value inaccuracies \ No newline at end of file +0.05: Refactored for efficiency, corrected sensor value inaccuracies +0.06: User settings are written to persistent storage, loaded on app start \ No newline at end of file diff --git a/apps/sensible/README.md b/apps/sensible/README.md index fcff3b0f9..8bf21ae8a 100644 --- a/apps/sensible/README.md +++ b/apps/sensible/README.md @@ -5,7 +5,9 @@ Collect all the sensor data from the Bangle.js 2, display the live readings in m ## Usage -The advertising packets will be recognised by [Pareto Anywhere](https://www.reelyactive.com/pareto/anywhere/) open source middleware and any other program which observes the standard packet types. Also convenient for testing individual sensors of the Bangle.js 2 via the menu interface. +The advertising packets will be recognised by [Pareto Anywhere](https://www.reelyactive.com/pareto/anywhere/) open source middleware and any other program which observes the standard packet types. See our [Bangle.js Development Guide](https://reelyactive.github.io/diy/banglejs-dev/) for details. Also convenient for testing individual sensors of the Bangle.js 2 via the menu interface. + +![SensiBLE in Pareto Anywhere](/BangleApps/apps/sensible/screenshot-pareto-anywhere.png) ## Features @@ -22,7 +24,7 @@ in the menu display, and broadcasts all sensor data readings _except_ accelerati ## Controls -Browse and control sensors using the standard Espruino menu interface. +Browse and control sensors using the standard Espruino menu interface. By default, all sensors _except_ the accelerometer are disabled. Sensors can be individually enabled/disabled via the menu. These settings are written to persistent storage (flash) and will be applied each time the SensiBLE app is loaded. ## Requests diff --git a/apps/sensible/metadata.json b/apps/sensible/metadata.json index df0421441..6715e2538 100644 --- a/apps/sensible/metadata.json +++ b/apps/sensible/metadata.json @@ -1,25 +1,28 @@ { -"id": "sensible", -"name": "SensiBLE", -"shortName": "SensiBLE", -"version": "0.05", -"description": "Collect, display and advertise real-time sensor data.", -"icon": "sensible.png", -"screenshots": [ - { "url": "screenshot-top.png" }, - { "url": "screenshot-acc.png" }, - { "url": "screenshot-bar.png" }, - { "url": "screenshot-gps.png" }, - { "url": "screenshot-hrm.png" }, - { "url": "screenshot-mag.png" } -], -"type": "app", -"tags": "tool,sensors,bluetooth", -"supports" : [ "BANGLEJS2" ], -"allow_emulator": true, -"readme": "README.md", -"storage": [ - { "name": "sensible.app.js", "url": "sensible.js" }, - { "name": "sensible.img", "url": "sensible-icon.js", "evaluate": true } -] + "id": "sensible", + "name": "SensiBLE", + "shortName": "SensiBLE", + "version": "0.06", + "description": "Collect, display and advertise real-time sensor data.", + "icon": "sensible.png", + "screenshots": [ + { "url": "screenshot-top.png" }, + { "url": "screenshot-acc.png" }, + { "url": "screenshot-bar.png" }, + { "url": "screenshot-gps.png" }, + { "url": "screenshot-hrm.png" }, + { "url": "screenshot-mag.png" } + ], + "type": "app", + "tags": "tool,sensors,bluetooth", + "supports" : [ "BANGLEJS2" ], + "allow_emulator": true, + "readme": "README.md", + "storage": [ + { "name": "sensible.app.js", "url": "sensible.js" }, + { "name": "sensible.img", "url": "sensible-icon.js", "evaluate": true } + ], + "data": [ + { "name": "sensible.data.json", "url": "settings.json", "storageFile": true } + ] } diff --git a/apps/sensible/screenshot-pareto-anywhere.png b/apps/sensible/screenshot-pareto-anywhere.png new file mode 100644 index 000000000..c411bca8a Binary files /dev/null and b/apps/sensible/screenshot-pareto-anywhere.png differ diff --git a/apps/sensible/sensible.js b/apps/sensible/sensible.js index 73c348556..8ec7d93d4 100644 --- a/apps/sensible/sensible.js +++ b/apps/sensible/sensible.js @@ -1,5 +1,5 @@ /** - * Copyright reelyActive 2021 + * Copyright reelyActive 2021-2022 * We believe in an open Internet of Things */ @@ -7,6 +7,8 @@ // Non-user-configurable constants const APP_ID = 'sensible'; const ESPRUINO_COMPANY_CODE = 0x0590; +const SETTINGS_FILENAME = 'sensible.data.json'; +const UPDATE_MILLISECONDS = 1000; const APP_ADVERTISING_DATA = [ 0x12, 0xff, 0x90, 0x05, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x3a, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x7d ]; @@ -19,16 +21,12 @@ let isBarMenu = false; let isGpsMenu = false; let isHrmMenu = false; let isMagMenu = false; -let isBarEnabled = true; -let isGpsEnabled = true; -let isHrmEnabled = true; -let isMagEnabled = true; let isNewAccData = false; let isNewBarData = false; let isNewGpsData = false; let isNewHrmData = false; let isNewMagData = false; - +let settings = require('Storage').readJSON(SETTINGS_FILENAME); // Menus @@ -51,9 +49,9 @@ let accMenu = { let barMenu = { "": { "title" : "- Barometer -" }, "State": { - value: isBarEnabled, + value: settings.isBarEnabled, format: v => v ? "On" : "Off", - onchange: v => { isBarEnabled = v; Bangle.setBarometerPower(v, APP_ID); } + onchange: v => { updateSetting('isBarEnabled', v); } }, "Altitude": { value: null }, "Press": { value: null }, @@ -63,9 +61,9 @@ let barMenu = { let gpsMenu = { "": { "title" : "- GPS -" }, "State": { - value: isGpsEnabled, + value: settings.isGpsEnabled, format: v => v ? "On" : "Off", - onchange: v => { isGpsEnabled = v; Bangle.setGPSPower(v, APP_ID); } + onchange: v => { updateSetting('isGpsEnabled', v); } }, "Lat": { value: null }, "Lon": { value: null }, @@ -77,9 +75,9 @@ let gpsMenu = { let hrmMenu = { "": { "title" : "- Heart Rate -" }, "State": { - value: isHrmEnabled, + value: settings.isHrmEnabled, format: v => v ? "On" : "Off", - onchange: v => { isHrmEnabled = v; Bangle.setHRMPower(v, APP_ID); } + onchange: v => { updateSetting('isHrmEnabled', v); } }, "BPM": { value: null }, "Confidence": { value: null }, @@ -88,9 +86,9 @@ let hrmMenu = { let magMenu = { "": { "title" : "- Magnetometer -" }, "State": { - value: isMagEnabled, + value: settings.isMagEnabled, format: v => v ? "On" : "Off", - onchange: v => { isMagEnabled = v; Bangle.setCompassPower(v, APP_ID); } + onchange: v => { updateSetting('isMagEnabled', v); } }, "x": { value: null }, "y": { value: null }, @@ -124,7 +122,7 @@ function transmitUpdatedSensorData() { isNewMagData = false; } - let interval = 1000 / data.length; + let interval = UPDATE_MILLISECONDS / data.length; NRF.setAdvertising(data, { showName: false, interval: interval }); } @@ -190,6 +188,23 @@ function toByteArray(value, numberOfBytes, isSigned) { } +// Enable the sensors as per the current settings +function enableSensors() { + Bangle.setBarometerPower(settings.isBarEnabled, APP_ID); + Bangle.setGPSPower(settings.isGpsEnabled, APP_ID); + Bangle.setHRMPower(settings.isHrmEnabled, APP_ID); + Bangle.setCompassPower(settings.isMagEnabled, APP_ID); +} + + +// Update the given setting and write to persistent storage +function updateSetting(name, value) { + settings[name] = value; + require('Storage').writeJSON(SETTINGS_FILENAME, settings); + enableSensors(); +} + + // Update acceleration Bangle.on('accel', function(newAcc) { acc = newAcc; @@ -260,9 +275,6 @@ Bangle.on('mag', function(newMag) { // On start: enable sensors and display main menu g.clear(); -Bangle.setBarometerPower(isBarEnabled, APP_ID); -Bangle.setGPSPower(isGpsEnabled, APP_ID); -Bangle.setHRMPower(isHrmEnabled, APP_ID); -Bangle.setCompassPower(isMagEnabled, APP_ID); +enableSensors(); E.showMenu(mainMenu); -setInterval(transmitUpdatedSensorData, 1000); \ No newline at end of file +setInterval(transmitUpdatedSensorData, UPDATE_MILLISECONDS); \ No newline at end of file diff --git a/apps/sensible/settings.json b/apps/sensible/settings.json new file mode 100644 index 000000000..90340a201 --- /dev/null +++ b/apps/sensible/settings.json @@ -0,0 +1,6 @@ +{ + "isBarEnabled": false, + "isGpsEnabled": false, + "isHrmEnabled": false, + "isMagEnabled": false +} \ No newline at end of file diff --git a/apps/simplest/ChangeLog b/apps/simplest/ChangeLog index e7ab5f2c3..a09bc47b9 100644 --- a/apps/simplest/ChangeLog +++ b/apps/simplest/ChangeLog @@ -4,3 +4,4 @@ 0.04: Use queueDraw(), update every minute, respect theme, use Lato font 0.05: Decided against custom font as it inceases the code size minimalism is useful when narrowing down issues +0.06: renamed some files diff --git a/apps/simplest/metadata.json b/apps/simplest/metadata.json index d3118fd22..d938aab9f 100644 --- a/apps/simplest/metadata.json +++ b/apps/simplest/metadata.json @@ -1,7 +1,7 @@ { "id": "simplest", "name": "Simplest Clock", - "version": "0.05", + "version": "0.06", "description": "The simplest working clock, acts as a tutorial piece", "icon": "simplest.png", "screenshots": [{"url":"screenshot_simplest.png"}], @@ -9,7 +9,7 @@ "tags": "clock", "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ - {"name":"simplest.app.js","url":"app.js"}, - {"name":"simplest.img","url":"icon.js","evaluate":true} + {"name":"simplest.app.js","url":"simplest.app.js"}, + {"name":"simplest.img","url":"simplest.icon.js","evaluate":true} ] } diff --git a/apps/simplest/app.js b/apps/simplest/simplest.app.js similarity index 97% rename from apps/simplest/app.js rename to apps/simplest/simplest.app.js index 582c4c2d5..4038212d0 100644 --- a/apps/simplest/app.js +++ b/apps/simplest/simplest.app.js @@ -13,7 +13,6 @@ function draw() { g.setFontAlign(0, 0); g.setColor(g.theme.fg); g.drawString(timeStr, w/2, h/2); - queueDraw(); } @@ -42,13 +41,12 @@ Bangle.on('lcdPower',on=>{ g.clear(); // Show launcher when middle button pressed -//Bangle.setUI("clock"); +// Bangle.setUI("clock"); // use clockupdown as it tests for issue #1249 Bangle.setUI("clockupdown", btn=> { draw(); }); - // Load widgets Bangle.loadWidgets(); Bangle.drawWidgets(); diff --git a/apps/simplest/icon.js b/apps/simplest/simplest.icon.js similarity index 100% rename from apps/simplest/icon.js rename to apps/simplest/simplest.icon.js diff --git a/apps/sleepphasealarm/ChangeLog b/apps/sleepphasealarm/ChangeLog index 47448167e..dbc3a0b82 100644 --- a/apps/sleepphasealarm/ChangeLog +++ b/apps/sleepphasealarm/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Respect Quiet Mode +0.03: Add compatibility for Bangle.js 2 and new firmware, added "Alarm at " for the alarm time diff --git a/apps/sleepphasealarm/app.js b/apps/sleepphasealarm/app.js index 0de0b9afc..39f9b59db 100644 --- a/apps/sleepphasealarm/app.js +++ b/apps/sleepphasealarm/app.js @@ -1,3 +1,4 @@ +const BANGLEJS2 = process.env.HWVERSION == 2; //# check for bangle 2 const alarms = require("Storage").readJSON("alarm.json",1)||[]; const active = alarms.filter(a=>a.on); @@ -52,21 +53,21 @@ active.forEach(alarm => { } }); -function drawString(s, x, y) { - g.clearRect(0,y-15,239,y+15); - g.reset(); - g.setFont("Vector",20); - g.setFontAlign(0,0); // align right bottom - g.drawString(s, x, y); +function drawString(s, y) { //# replaced x: always centered + g.reset(); //# moved up to prevent blue background + g.clearRect(0, y - 12, 239, y + 8); //# minimized upper+lower clearing + g.setFont("Vector", 20); + g.setFontAlign(0, 0); // align centered + g.drawString(s, g.getWidth() / 2, y); //# set x to center } function drawApp() { - g.clearRect(0,24,239,215); + g.clearRect(0,24,239,215); //# no problem var alarmHour = nextAlarm.getHours(); var alarmMinute = nextAlarm.getMinutes(); if (alarmHour < 10) alarmHour = "0" + alarmHour; if (alarmMinute < 10) alarmMinute = "0" + alarmMinute; - const s = alarmHour + ":" + alarmMinute + "\n\n"; + const s = "Alarm at " + alarmHour + ":" + alarmMinute + "\n\n"; //# make distinct to time E.showMessage(s, "Sleep Phase Alarm"); function drawTime() { @@ -78,12 +79,20 @@ function drawApp() { if (nowHour < 10) nowHour = "0" + nowHour; if (nowMinute < 10) nowMinute = "0" + nowMinute; if (nowSecond < 10) nowSecond = "0" + nowSecond; - const time = nowHour + ":" + nowMinute + ":" + nowSecond; - drawString(time, 120, 140); + const time = nowHour + ":" + nowMinute + (BANGLEJS2 ? "" : ":" + nowSecond); //# hide seconds on bangle 2 + drawString(time, BANGLEJS2 ? 85 : 105); //# remove x, adjust height for bangle 2 an newer firmware } } - setInterval(drawTime, 500); // 2Hz + if (BANGLEJS2) { + drawTime(); + setTimeout(_ => { + drawTime(); + setInterval(drawTime, 60000); + }, 60000 - Date.now() % 60000); //# every new minute on bangle 2 + } else { + setInterval(drawTime, 500); // 2Hz + } } var buzzCount = 19; @@ -104,8 +113,8 @@ function buzz() { var minAlarm = new Date(); var measure = true; if (nextAlarm !== undefined) { + Bangle.loadWidgets(); //# correct widget load draw order Bangle.drawWidgets(); - Bangle.loadWidgets(); // minimum alert 30 minutes early minAlarm.setTime(nextAlarm.getTime() - (30*60*1000)); @@ -116,7 +125,7 @@ if (nextAlarm !== undefined) { if (swest !== undefined) { if (Bangle.isLCDOn()) { - drawString(swest ? "Sleep" : "Awake", 120, 180); + drawString(swest ? "Sleep" : "Awake", BANGLEJS2 ? 150 : 180); //# remove x, adjust height } } @@ -133,6 +142,6 @@ if (nextAlarm !== undefined) { E.showMessage('No Alarm'); setTimeout(load, 1000); } -// BTN2 to menu, BTN3 to main -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); -setWatch(() => load(), BTN3, { repeat: false, edge: "falling" }); +// BTN2 to menu, BTN3 to main # on bangle 2 only BTN to main +if (!BANGLEJS2) setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +setWatch(() => load(), BANGLEJS2 ? BTN : BTN3, { repeat: false, edge: "falling" }); diff --git a/apps/sleepphasealarm/metadata.json b/apps/sleepphasealarm/metadata.json index f74c97b54..ed0f21028 100644 --- a/apps/sleepphasealarm/metadata.json +++ b/apps/sleepphasealarm/metadata.json @@ -2,11 +2,11 @@ "id": "sleepphasealarm", "name": "SleepPhaseAlarm", "shortName": "SleepPhaseAlarm", - "version": "0.02", + "version": "0.03", "description": "Uses the accelerometer to estimate sleep and wake states with the principle of Estimation of Stationary Sleep-segments (ESS, see https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en). This app will read the next alarm from the alarm application and will wake you up to 30 minutes early at the best guessed time when you are almost already awake.", "icon": "app.png", "tags": "alarm", - "supports": ["BANGLEJS"], + "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ {"name":"sleepphasealarm.app.js","url":"app.js"}, {"name":"sleepphasealarm.img","url":"app-icon.js","evaluate":true} diff --git a/apps/speedalt2/ChangeLog b/apps/speedalt2/ChangeLog index 09a5eb8cc..c58795e3b 100644 --- a/apps/speedalt2/ChangeLog +++ b/apps/speedalt2/ChangeLog @@ -1,3 +1,12 @@ 0.01: Initial import. -0.02: Add swipe to change screens. -0.03: Misc memory and screen optimisations. +0.02: Misc development. +0.03: Enable screen off. +0.04: Vibrate once on no fix, twice on fix. +0.05: Add setting to turn vibrate on/off. +0.06: Tweaks to vibration settings. +0.07: Switch to BTN1 for Max toggle and reset function. +0.08: New features. Added waypoints file and distance to selected waypoint display. Added integration with GPS Setup module to switch GPS to low power mode when screen off. Save display settings and restore when app restarted. +0.09: Add third screen mode with large clock and waypoint selection display to ease visibility in bright daylight. +0.10: Add Kalman filter to smooth the speed and altitude values. Can be disabled in settings. +1.06: Misc memory and screen optimisations. +1.10: Adds Kalman filter. diff --git a/apps/speedalt2/metadata.json b/apps/speedalt2/metadata.json index a78039f54..f05611338 100644 --- a/apps/speedalt2/metadata.json +++ b/apps/speedalt2/metadata.json @@ -2,7 +2,7 @@ "id": "speedalt2", "name": "GPS Adventure Sports II", "shortName":"GPS Adv Sport II", - "version":"0.03", + "version":"1.10", "description": "GPS speed, altitude and distance to waypoint display. Designed for easy viewing and use during outdoor activities such as para-gliding, hang-gliding, sailing, cycling etc.", "icon": "app.png", "type": "app", diff --git a/apps/widram/ChangeLog b/apps/widram/ChangeLog index 4c21f3ace..e7b406081 100644 --- a/apps/widram/ChangeLog +++ b/apps/widram/ChangeLog @@ -1 +1,2 @@ 0.01: New Widget! +0.02: Now also visible on Bangle.js 2 diff --git a/apps/widram/metadata.json b/apps/widram/metadata.json index 8ea309ebf..19ae6d311 100644 --- a/apps/widram/metadata.json +++ b/apps/widram/metadata.json @@ -2,8 +2,8 @@ "id": "widram", "name": "RAM Widget", "shortName": "RAM Widget", - "version": "0.01", - "description": "Display your Bangle's available RAM percentage in a widget", + "version": "0.02", + "description": "Display your Bangle's RAM usage percentage in a widget", "icon": "widget.png", "type": "widget", "tags": "widget", diff --git a/apps/widram/widget.js b/apps/widram/widget.js index dc7fed6c3..210c85357 100644 --- a/apps/widram/widget.js +++ b/apps/widram/widget.js @@ -1,11 +1,15 @@ (() => { function draw() { + BANGLEJS2 = process.env.HWVERSION==2; g.reset(); var m = process.memory(); - var pc = Math.round(m.usage*100/m.total); + var percent = Math.round(m.usage*100/m.total); g.drawImage(atob("BwgBqgP////AVQ=="), this.x+(24-7)/2, this.y+4); - g.setColor(pc>70 ? "#ff0000" : (pc>50 ? "#ffff00" : "#ffffff")); - g.setFont("6x8").setFontAlign(0,0).drawString(pc+"%", this.x+12, this.y+20, true/*solid*/); + if (!BANGLEJS2) + g.setColor(percent>70 ? "#ff0000" : (percent>50 ? "#ffff00" : "#ffffff")); + else + g.setColor(percent>70 ? "#f00" : (percent>50 ? "#00f" : "#0f0")); + g.setFont("6x8").setFontAlign(0,0).drawString(percent+"%", this.x+12, this.y+20, true/*solid*/); } var ramInterval; Bangle.on('lcdPower', function(on) { @@ -20,4 +24,4 @@ } }); WIDGETS["ram"]={area:"tl",width: 24,draw:draw}; -})() +})(); diff --git a/apps/wpmoto/README.md b/apps/wpmoto/README.md new file mode 100644 index 000000000..96c72ff55 --- /dev/null +++ b/apps/wpmoto/README.md @@ -0,0 +1,158 @@ +# Waypointer Moto + +Waypointer Moto is a GPS navigation aid intended to be attached to +the handlebars of a motorcycle. +It uses the GPS to find out which direction it's +travelling and shows the direction and distance to the destination +"as the crow flies". It gives you an indication of where to go, +but exploring and navigating the environment is left up to the user. + +![](watch-on-bike.jpeg) + +(Please note that it would be foolish in the extreme to rely on this +as your only navigation aid! Make sure you read this entire document +before using the app for navigation so that you know the drawbacks +and shortcomings.) + +## App usage + +### Main screen + +![](screenshot.png) + +The main screen shows the direction arrow, the distance to the waypoint, +and the name of the selected waypoint. + +It also shows the status of the GPS fix in the colour of the arrow: + + * Red: no GPS fix at all + * Yellow: GPS location, but no GPS course (probably you're moving too slowly); + in this case the direction of travel comes from the compass bearing instead + of the GPS course, but note that the compass is unreliable + * White: GPS fix includes both location and course, and the GPS course is used + to determine the direction of travel + +### Select a waypoint + +![](screenshot-menu.png) + +Press the middle button (`BTN2`) to enter the menu, choose a waypoint using +the up/down arrows, and use the middle button again to select a waypoint and +return to the main screen. + +### Add a waypoint + +Press the middle button (`BTN2`) to enter the menu, and select the "+ Here" +option. This will add a waypoint named "WP*n*" marking your current location, +where "*n*" is the next unused number. + +### Delete a waypoint + +![](screenshot-delete.png) + +Select a waypoint using the menu. Once the waypoint is selected and you're +back on the main screen, press either the top or bottom button (`BTN1` or +`BTN3`). Confirm that you want to delete the waypoint with the middle +button (`BTN2`). + +## Waypoint editor + +With the Bangle.js app loader connected to the watch, find the +Waypointer Moto app and click on the floppy disk icon: + +![](floppy-disk.png) + +This will load up the waypoint editor: + +![](editor.png) + +### Add a waypoint + +Use the map to find your destination. Clicking on the map will +populate the latitude/longitude input boxes with the coordinates +of the point you clicked on. Type in a name for the waypoint and +click "Add Waypoint". Click "Upload" to send the updated list of +waypoints to the watch. + +### Edit a waypoint + +Click on the pencil icon next to the waypoint you wish to edit. +This will remove the waypoint from the list and populate the +input boxes. +Edit the coordinates by hand, or by clicking on the map. Edit +the name if you want. Click "Add Waypoint" to save the waypoint +back to the list. Click "Upload" to send the updated list of +waypoints to the watch. + +### Delete a waypoint + +Click on the pencil icon next to the waypoint you wish to edit. +This will remove the waypoint from the list. +Click "Upload" to send the updated list of waypoints to the watch. + +## Mounting the watch on the bike + +There is a 3d-printable "artificial wrist" which will fit over a 7/8" +handlebar and allow the watch strap to tighten up. +Alternatively, in a pinch you can strap the watch around a glove or a sponge +or anything else that will pad out the space so that the watch is a tight +fit. + +The 3d-printed part should be a snug fit on the handlebar so that it does +not flop around. If it is too loose, line it with a layer or 2 of tape. + +[Download the handlebar mount STL »](handlebar-mount.stl) + +[Download the handlebar mount FreeCAD source »](handlebar-mount.FCStd) + +![](handlebar-mount.png) + +![](handlebar-mount.jpeg) + +## Comparison to Way Pointer + +Compared to the original Way Pointer app, Waypointer Moto: + + * removes the numerical display of compass bearing + * makes the distance text bigger + * uses a higher-resolution arrow icon + * has a visual indication of the GPS status (the arrow colour) + * uses GPS course instead of compass bearing + * has OpenStreetMap integration in the waypoint editor + * uses Bangle.js menus to select waypoints instead of custom UI + * can add new waypoints from inside the app without requiring a blank slot + * can delete waypoints from inside the app without needing the PC + * still uses the same `waypoints.json` file + +## Gotchas + +Waypointer Moto derives your current heading from the GPS course +rather than the compass, whenever GPS course is available. +The compass bearing is based on the angle the watch is held, but +the GPS course is based on the direction it's *travelling*. If the +watch is not aligned with the direction of travel of the vehicle +then the arrow will not point in the correct direction. + +When travelling too slowly, there is no GPS course information, so the +app reverts to using the compass (and draws it in yellow), but +the compass is not very reliable, and I +have especially found it not to be reliable when placed on a motorcyle, +maybe because of all the metal in the immediate vicinity. So if +the arrow is not drawn in white, then you should probably not trust +it. If you're not sure, just ride in a straight line until the arrow +turns white again. + +## Possible Future Enhancements + + - "routes" with multiple waypoints; automatically step from one + waypoint to the next when you get near to it + - some way to manually input coordinates directly on the watch + - make the text & arrow more legible in direct sunlight + - integrate a charging connector into the handlebar mount + - upstream the map integration to the other waypoint apps + +## Acknowledgements + +Waypointer Moto is a project by [James Stanley](https://incoherency.co.uk/). It is a derivative of [Adam Schmalhofer's](https://github.com/adamschmalhofer) Way Pointer app, which is in turn a derivative of +[jeffmer's](https://github.com/jeffmer/JeffsBangleAppsDev) GPS +Navigation and Compass Navigation apps. diff --git a/apps/wpmoto/app.js b/apps/wpmoto/app.js new file mode 100644 index 000000000..8a0e86ef6 --- /dev/null +++ b/apps/wpmoto/app.js @@ -0,0 +1,288 @@ +var loc = require("locale"); + +var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"NONE"}]; +var wp = waypoints[0]; +var wp_bearing = 0; +var candraw = true; + +var direction = 0; +var dist = 0; + +var savedfix; + +var previous = { + dst: '', + wp_name: '', + course: 180, + selected: false, +}; + +/*** Drawing ***/ + +var pal_by = new Uint16Array([0x0000,0xFFC0],0,1); // black, yellow +var pal_bw = new Uint16Array([0x0000,0xffff],0,1); // black, white +var pal_bb = new Uint16Array([0x0000,0x07ff],0,1); // black, blue +var pal_br = new Uint16Array([0x0000,0xf800],0,1); // black, red +var pal_compass = pal_by; + +var buf = Graphics.createArrayBuffer(160,160,1, {msb:true}); +var arrow_img = require("heatshrink").decompress(atob("vF4wJC/AEMYBxs8Bxt+Bxv/BpkB/+ABxcD//ABxcH//gBxcP//wBxcf//4Bxc///8Bxd///+OxgABOxgABPBR2BAAJ4KOwIABPBR2BAAJ4KOwIABPBR2BAAJ4KOwIABPBQNCPBR2DPBR2DPBR2DPBR2DPBR2DPBR2DPBR2DPBQNEPBB2FPBB2FPBB2FPBB2FPBB2FPBB2FPBB2FPBANGPAx2HPAx2HPAx2HPAx2HPAx2HPAx2HeJTeJB34O/B34O/B34O/B34O/B34O/B34O/B34O/B34OTAH4AT")); + +function flip1(x,y,palette) { + g.drawImage({width:160,height:160,bpp:1,buffer:buf.buffer, palette:palette},x,y); + buf.clear(); +} + +function flip2_bw(x,y) { + g.drawImage({width:160,height:40,bpp:1,buffer:buf.buffer, palette:pal_bw},x,y); + buf.clear(); +} + +function flip2_bb(x,y) { + g.drawImage({width:160,height:40,bpp:1,buffer:buf.buffer, palette:pal_bb},x,y); + buf.clear(); +} + +function drawCompass(course) { + if (!candraw) return; + + previous.course = course; + + buf.setColor(1); + buf.fillCircle(80,80, 79); + buf.setColor(0); + buf.fillCircle(80,80, 69); + buf.setColor(1); + buf.drawImage(arrow_img, 80, 80, {rotate:radians(course)} ); + var palette = pal_br; + if (savedfix !== undefined && savedfix.fix !== 0) palette = pal_compass; + flip1(40, 30, palette); +} + +function drawN(force){ + if (!candraw) return; + + buf.setFont("Vector",24); + var dst = loc.distance(dist); + + // distance on left + if (force || previous.dst !== dst) { + previous.dst = dst; + buf.setColor(1); + buf.setFontAlign(-1, -1); + buf.setFont("Vector",40); + buf.drawString(dst,0,0); + flip2_bw(8, 200); + } + + // waypoint name on right + if (force || previous.wp_name !== wp.name) { + previous.wp_name = wp.name; + buf.setColor(1); + buf.setFontAlign(1, -1); + buf.setFont("Vector", 15); + buf.drawString(wp.name, 80, 0); + flip2_bw(160, 220); + } +} + +function drawAll(force) { + if (!candraw) return; + + g.setColor(1,1,1); + drawN(force); + drawCompass(direction); +} + +/*** Heading ***/ + +var heading = 0; +function newHeading(m,h){ + var s = Math.abs(m - h); + var delta = (m>h)?1:-1; + if (s>=180){s=360-s; delta = -delta;} + if (s<2) return h; + var hd = h + delta*(1 + Math.round(s/5)); + if (hd<0) hd+=360; + if (hd>360)hd-= 360; + return hd; +} + +var CALIBDATA = require("Storage").readJSON("magnav.json",1)||null; + +function tiltfixread(O,S){ + var start = Date.now(); + var m = Bangle.getCompass(); + var g = Bangle.getAccel(); + m.dx =(m.x-O.x)*S.x; m.dy=(m.y-O.y)*S.y; m.dz=(m.z-O.z)*S.z; + var d = Math.atan2(-m.dx,m.dy)*180/Math.PI; + if (d<0) d+=360; + var phi = Math.atan(-g.x/-g.z); + var cosphi = Math.cos(phi), sinphi = Math.sin(phi); + var theta = Math.atan(-g.y/(-g.x*sinphi-g.z*cosphi)); + var costheta = Math.cos(theta), sintheta = Math.sin(theta); + var xh = m.dy*costheta + m.dx*sinphi*sintheta + m.dz*cosphi*sintheta; + var yh = m.dz*sinphi - m.dx*cosphi; + var psi = Math.atan2(yh,xh)*180/Math.PI; + if (psi<0) psi+=360; + return psi; +} + +function read_heading() { + if (savedfix !== undefined && !isNaN(savedfix.course)) { + Bangle.setCompassPower(0); + heading = savedfix.course; + pal_compass = pal_bw; + } else { + var d = tiltfixread(CALIBDATA.offset,CALIBDATA.scale); + Bangle.setCompassPower(1); + heading = newHeading(d,heading); + pal_compass = pal_by; + } + + direction = wp_bearing - heading; + if (direction < 0) direction += 360; + if (direction > 360) direction -= 360; + drawCompass(direction); +} + + +/*** Maths ***/ + +function radians(a) { + return a*Math.PI/180; +} + +function degrees(a) { + var d = a*180/Math.PI; + return (d+360)%360; +} + +function bearing(a,b){ + var delta = radians(b.lon-a.lon); + var alat = radians(a.lat); + var blat = radians(b.lat); + var y = Math.sin(delta) * Math.cos(blat); + var x = Math.cos(alat)*Math.sin(blat) - Math.sin(alat)*Math.cos(blat)*Math.cos(delta); + return Math.round(degrees(Math.atan2(y, x))); +} + +function distance(a,b){ + var x = radians(a.lon-b.lon) * Math.cos(radians((a.lat+b.lat)/2)); + var y = radians(b.lat-a.lat); + return Math.round(Math.sqrt(x*x + y*y) * 6371000); +} + +/*** Waypoints ***/ + +function addCurrentWaypoint() { + var wpnum = 0; + var ok = false; + // XXX: O(n^2) search for lowest unused WP number + while (!ok) { + ok = true; + for (var i = 0; i < waypoints.length && ok; i++) { + if (waypoints[i].name == ("WP"+wpnum)) { + wpnum++; + ok = false; + } + } + } + + waypoints.push({ + name: "WP" + wpnum, + lat: savedfix.lat, + lon: savedfix.lon, + }); + wp = waypoints[waypoints.length-1]; + saveWaypoints(); +} + +function saveWaypoints() { + require("Storage").writeJSON("waypoints.json", waypoints); +} + +function deleteWaypoint(w) { + for (var i = 0; i < waypoints.length; i++) { + if (waypoints[i] == w) { + waypoints.splice(i, 1); + saveWaypoints(); + wp = {name:"NONE"}; + } + } +} + +/*** Setup ***/ + +function onGPS(fix) { + savedfix = fix; + + if (fix !== undefined && fix.fix == 1){ + dist = distance(fix, wp); + if (isNaN(dist)) dist = 0; + wp_bearing = bearing(fix, wp); + if (isNaN(wp_bearing)) wp_bearing = 0; + drawN(); + } +} + +function startTimers() { + setInterval(function() { + Bangle.setLCDPower(1); + read_heading(); + }, 500); +} + +function addWaypointToMenu(menu, i) { + menu[waypoints[i].name] = function() { + wp = waypoints[i]; + mainScreen(); + }; +} + +function mainScreen() { + E.showMenu(); + candraw = true; + drawAll(true); + + Bangle.setUI("updown", function(v) { + if (v === undefined) { + candraw = false; + var menu = { + "": { "title": "-- Waypoints --" }, + }; + for (let i = 0; i < waypoints.length; i++) { + addWaypointToMenu(menu, i); + } + menu["+ Here"] = function() { + addCurrentWaypoint(); + mainScreen(); + }; + menu["< Back"] = mainScreen; + E.showMenu(menu); + } else { + candraw = false; + E.showPrompt("Delete waypoint: " + wp.name + "?").then(function(confirmed) { + var name = wp.name; + if (confirmed) { + deleteWaypoint(wp); + E.showAlert("Waypoint deleted: " + name).then(mainScreen); + } else { + mainScreen(); + } + }); + } + }); +} + +Bangle.on('kill',()=>{ + Bangle.setCompassPower(0); + Bangle.setGPSPower(0); +}); + +g.clear(); +Bangle.setLCDBrightness(1); +Bangle.setGPSPower(1); +startTimers(); +Bangle.on('GPS', onGPS); +mainScreen(); diff --git a/apps/wpmoto/arrow.png b/apps/wpmoto/arrow.png new file mode 100644 index 000000000..870c7b6b2 Binary files /dev/null and b/apps/wpmoto/arrow.png differ diff --git a/apps/wpmoto/editor.png b/apps/wpmoto/editor.png new file mode 100644 index 000000000..0d2f9841b Binary files /dev/null and b/apps/wpmoto/editor.png differ diff --git a/apps/wpmoto/floppy-disk.png b/apps/wpmoto/floppy-disk.png new file mode 100644 index 000000000..dde8500c9 Binary files /dev/null and b/apps/wpmoto/floppy-disk.png differ diff --git a/apps/wpmoto/handlebar-mount.FCStd b/apps/wpmoto/handlebar-mount.FCStd new file mode 100644 index 000000000..a370c1090 Binary files /dev/null and b/apps/wpmoto/handlebar-mount.FCStd differ diff --git a/apps/wpmoto/handlebar-mount.jpeg b/apps/wpmoto/handlebar-mount.jpeg new file mode 100644 index 000000000..c4556a0d0 Binary files /dev/null and b/apps/wpmoto/handlebar-mount.jpeg differ diff --git a/apps/wpmoto/handlebar-mount.png b/apps/wpmoto/handlebar-mount.png new file mode 100644 index 000000000..da5adf7a7 Binary files /dev/null and b/apps/wpmoto/handlebar-mount.png differ diff --git a/apps/wpmoto/handlebar-mount.stl b/apps/wpmoto/handlebar-mount.stl new file mode 100644 index 000000000..966d0c327 Binary files /dev/null and b/apps/wpmoto/handlebar-mount.stl differ diff --git a/apps/wpmoto/icon.js b/apps/wpmoto/icon.js new file mode 100644 index 000000000..fc8eee898 --- /dev/null +++ b/apps/wpmoto/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4kA///tVK/feuekkEh1dSnnn5P2imlgdr221vvv0E5x9z8dqoEpMf4AqgMQCysRiIYUgMd6IXVqc1iIXXAAo2NiIXBivdAAfVGwxwCAAgXBicmswACsVRGAsRqoAEqIXC0QXDs0lGAkBisrBomBC4WqGAloMIkRqW72wNDlvTC4QwEwIvDLoOr3e7KwkzmsdmczxAABwaQFF4QwEC4SAGR4pfBGAO2kQABlQXIX4wlHL4LQNX5IXNDw4XygdZ96MFF58NvP8C6Mzu93uF9+oXQrQWBAAPU/5kPgoWDu+UoIQJ7vR6IGCm4XEz9MC5HMAAvHC4mc4gWHk93zPsC5F58oWHgQOE//8//M//+5mf9vAFxFwOQef5nu9wbB5nOiNQBoInCCYMCk8FjnM7qkB5lEp3//udRoKlBuueDwMyC4MojnJz2dmEA/1EovDn3d6nEiEHv3pzOc4oXB1nJ0Wo7JVBjnE/td6IxBgtQu/u4ci1vs6EAj+S3eynvBgEP92Z/+XzIXBiF59GOte27goB5OrlGDlWcMAP3SgJvBusBgF/61sycrlPFgvJsWZzMrziGB84XDvlBg+excp9N73P1gbQB5//+lEiMAi93vwaBz4XC1ep5OS2f9gPJlWZ93d+lBqNfzn//N5+lAg+cF4OZF4UA52LlWi3RfBSANEAAVBgEHz+W3VzlepVANczW73ep+L4CgNTnrfBAAPc8drUAOcR4MB/PYwefAwIXCjvRdgIABgvO7Ui1PMX4MA5n+96+BC4cRiIXDKAPOzPvIwIABhsc4oPEDAIGFhqhB4K2BACY+EAH4AG")) diff --git a/apps/wpmoto/metadata.json b/apps/wpmoto/metadata.json new file mode 100644 index 000000000..4e6c3497a --- /dev/null +++ b/apps/wpmoto/metadata.json @@ -0,0 +1,18 @@ +{ + "id": "wpmoto", + "name": "Waypointer Moto", + "shortName": "Waypointer Moto", + "version": "0.01", + "description": "Waypoint-based motorcycle navigation aid", + "icon": "wpmoto.png", + "tags": "tool,outdoors,gps", + "supports": ["BANGLEJS"], + "screenshots": [{"url":"screenshot.png"},{"url":"screenshot-menu.png"},{"url":"screenshot-delete.png"}], + "readme": "README.md", + "interface": "wpmoto.html", + "storage": [ + {"name":"wpmoto.app.js","url":"app.js"}, + {"name":"wpmoto.img","url":"icon.js","evaluate":true} + ], + "data": [{"name":"waypoints.json","url":"waypoints.json"}] +} diff --git a/apps/wpmoto/screenshot-delete.png b/apps/wpmoto/screenshot-delete.png new file mode 100644 index 000000000..4669a6cd0 Binary files /dev/null and b/apps/wpmoto/screenshot-delete.png differ diff --git a/apps/wpmoto/screenshot-menu.png b/apps/wpmoto/screenshot-menu.png new file mode 100644 index 000000000..cd4cedf2f Binary files /dev/null and b/apps/wpmoto/screenshot-menu.png differ diff --git a/apps/wpmoto/screenshot.png b/apps/wpmoto/screenshot.png new file mode 100644 index 000000000..756e54118 Binary files /dev/null and b/apps/wpmoto/screenshot.png differ diff --git a/apps/wpmoto/watch-on-bike.jpeg b/apps/wpmoto/watch-on-bike.jpeg new file mode 100644 index 000000000..c97fe9412 Binary files /dev/null and b/apps/wpmoto/watch-on-bike.jpeg differ diff --git a/apps/wpmoto/waypoints.json b/apps/wpmoto/waypoints.json new file mode 100644 index 000000000..8a4ab83b8 --- /dev/null +++ b/apps/wpmoto/waypoints.json @@ -0,0 +1,5 @@ +[ + { + "name":"NONE" + }, +] diff --git a/apps/wpmoto/wpmoto.html b/apps/wpmoto/wpmoto.html new file mode 100644 index 000000000..2fb7c9455 --- /dev/null +++ b/apps/wpmoto/wpmoto.html @@ -0,0 +1,198 @@ + + + + + + + + + +

List of waypoints

+ + + + + + + + + + + + +
NameLat.Long.Actions
+
+

Add a new waypoint

+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+ + + + + + + + diff --git a/apps/wpmoto/wpmoto.png b/apps/wpmoto/wpmoto.png new file mode 100644 index 000000000..fea1d128a Binary files /dev/null and b/apps/wpmoto/wpmoto.png differ diff --git a/bin/create_apps_json.sh b/bin/create_apps_json.sh index dd883b22a..665079fc6 100755 --- a/bin/create_apps_json.sh +++ b/bin/create_apps_json.sh @@ -37,7 +37,7 @@ for app in apps/*/; do done echo "]" >> "$outfile" -if [ -z "$1"]; then +if [ -z "$1" ]; then # Running with no arguments: prevent accidental commit of modified apps.json. # You can use `create_apps.json.sh apps.json` if you really want to both # overwrite and still commit apps.json @@ -45,4 +45,4 @@ if [ -z "$1"]; then echo "Told git to ignore modified apps.json." # If you want to unignore it, use # 'git update-index --no-skip-worktree apps.json' -fi \ No newline at end of file +fi diff --git a/bin/firmwaremaker.js b/bin/firmwaremaker.js index 9f7758ee5..1c2d9cb77 100755 --- a/bin/firmwaremaker.js +++ b/bin/firmwaremaker.js @@ -57,7 +57,7 @@ function fileGetter(url) { Promise.all(APPS.map(appid => { try { - var app = JSON.parse(fs.readFileSync(APPDIR + "/" + appid + "metadata.json").toString()); + var app = JSON.parse(fs.readFileSync(APPDIR + "/" + appid + "/metadata.json").toString()); } catch (e) { throw new Error(`App ${appid} not found`); } @@ -77,6 +77,7 @@ Promise.all(APPS.map(appid => { js += `\x10if (E.CRC32(require('Storage').read(${JSON.stringify(file.name)}))!=${file.crc}){console.log("${file.name} invalid");FAIL++}\n`; }*/ }); + // js = js.replace(/\x10/g,""); // remove the echo-off characters (for testing only) fs.writeFileSync(OUTFILE, js); console.log("Output written to "+OUTFILE); }); diff --git a/bin/firmwaremaker_c.js b/bin/firmwaremaker_c.js index e7042d2c3..7940e551d 100755 --- a/bin/firmwaremaker_c.js +++ b/bin/firmwaremaker_c.js @@ -133,7 +133,7 @@ function evaluateFile(file) { Promise.all(APPS.map(appid => { try { - var app = JSON.parse(fs.readFileSync(APPDIR + "/" + appid + "metadata.json").toString()); + var app = JSON.parse(fs.readFileSync(APPDIR + "/" + appid + "/metadata.json").toString()); } catch (e) { throw new Error(`App ${appid} not found`); } diff --git a/core b/core index 3093d78a5..f97a128a2 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 3093d78a5d752cbf03ea8f9a1a7c0b50b9c8123b +Subproject commit f97a128a28b409c576f66c63c87905f26a5cfd8b diff --git a/index.html b/index.html index 7e818ee72..04851f28e 100644 --- a/index.html +++ b/index.html @@ -51,8 +51,8 @@
  • My Apps
  • -
  • - About +
  • + More...
  • @@ -111,7 +111,7 @@ -