forked from espruino/BangleApps
-
Notifications
You must be signed in to change notification settings - Fork 0
/
firmware.js
45 lines (45 loc) · 42.4 KB
/
firmware.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
require('Storage').write(".bootcde","E.setFlags({pretokenise:1});\nvar startapp;\ntry {\n startapp = require('Storage').readJSON('+start');\n} catch (e) {}\nif (startapp) {\n eval(require(\"Storage\").read(startapp.src));\n} else {\n delete startapp;\n setWatch(function displayMenu() {\n Bangle.setLCDMode(\"direct\");\n g.clear();\n clearInterval();\n clearWatch();\n Bangle.removeAllListeners();\n var s = require(\"Storage\");\n\n var apps = s.list().filter(a=>a[0]=='+').map(app=>{\n try { return s.readJSON(app); }\n catch (e) { return {name:\"DEAD: \"+app.substr(1)} }\n }).filter(app=>app.type==\"app\" || app.type==\"clock\" || !app.type);\n apps.sort((a,b)=>{\n var n=(0|a.sortorder)-(0|b.sortorder);\n if (n) return n; // do sortorder first\n if (a.name<b.name) return -1;\n if (a.name>b.name) return 1;\n return 0;\n });\n var selected = 0;\n var menuScroll = 0;\n var menuShowing = false;\n\n function drawMenu() {\n g.setFont(\"6x8\",2);\n g.setFontAlign(-1,0);\n var n = 3;\n if (selected>=n+menuScroll) menuScroll = 1+selected-n;\n if (selected<menuScroll) menuScroll = selected;\n if (menuScroll) g.fillPoly([120,0,100,20,140,20]);\n else g.clearRect(100,0,140,20);\n if (apps.length>n+menuScroll) g.fillPoly([120,239,100,219,140,219]);\n else g.clearRect(100,219,140,239);\n for (var i=0;i<n;i++) {\n var app = apps[i+menuScroll];\n if (!app) break;\n var y = 24+i*64;\n if (i+menuScroll==selected) {\n g.setColor(0.3,0.3,0.3);\n g.fillRect(0,y,239,y+63);\n g.setColor(1,1,1);\n g.drawRect(0,y,239,y+63);\n } else\n g.clearRect(0,y,239,y+63);\n g.drawString(app.name,64,y+32);\n var icon=undefined;\n if (app.icon) icon = s.read(app.icon);\n if (icon) try {g.drawImage(icon,8,y+8);} catch(e){}\n }\n }\n drawMenu();\n setWatch(function() {\n if (selected>0) {\n selected--;\n drawMenu();\n }\n }, BTN1, {repeat:true});\n setWatch(function() {\n if (selected+1<apps.length) {\n selected++;\n drawMenu();\n }\n }, BTN3, {repeat:true});\n setWatch(function() { // run\n if (!apps[selected].src) return;\n clearWatch();\n g.clear();\n g.setFont(\"6x8\",2);\n g.setFontAlign(0,0);\n g.drawString(\"Loading...\",120,120);\n // load like this so we ensure we've cleared out our RAM\n var cmd = 'eval(require(\"Storage\").read(\"'+apps[selected].src+'\"));';\n setTimeout(process.memory,10); // force GC\n setTimeout(cmd,20);\n // re-add the menu button if we're going to the clock\n if (apps[selected].type==\"clock\") {\n setWatch(displayMenu, BTN2, {repeat:false,edge:\"falling\"});\n } else {\n delete WIDGETS;\n delete WIDGETPOS;\n delete drawWidgets;\n }\n }, BTN2, {repeat:true,edge:\"falling\"});\n }, BTN2, {repeat:false,edge:\"falling\"}); // menu on middle button\n\n var WIDGETPOS={tl:32,tr:g.getWidth()-32,bl:32,br:g.getWidth()-32};\n var WIDGETS={};\n function drawWidgets() {\n Object.keys(WIDGETS).forEach(k=>WIDGETS[k].draw());\n }\n var clockApp = require(\"Storage\").list().filter(a=>a[0]=='+').map(app=>{\n try { return require(\"Storage\").readJSON(app); }\n catch (e) {}\n }).find(app=>app.type==\"clock\");\n if (clockApp) eval(require(\"Storage\").read(clockApp.src));\n else E.showMessage(\"No Clock Found\");\n delete clockApp;\n require(\"Storage\").list().filter(a=>a[0]=='=').forEach(widget=>eval(require(\"Storage\").read(widget)));\n setTimeout(drawWidgets,100);\n}\n");
require('Storage').write("+mclock",{"name":"Morphing Clock","type":"clock","icon":"*mclock","src":"-mclock","sortorder":-10,"files":"+mclock,-mclock,*mclock"});
require('Storage').write("-mclock","// Enable 'Set Current Time' in Settings -> Communications before sending\n(function(){ // make our own scope so this is GC'd when intervals are cleared\n// Offscreen buffer\nvar buf = Graphics.createArrayBuffer(240,86,1,{msb:true});\nfunction flip() {\n g.setColor(1,1,1);\n g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer},0,50);\n}\n// The last time that we displayed\nvar lastTime = \" \";\n// If animating, this is the interval's id\nvar animInterval;\n\n/* Get array of lines from digit d to d+1.\n n is the amount (0..1)\n maxFive is true is this digit only counts 0..5 */\nconst DIGITS = {\n\" \":n=>[],\n\"0\":n=>[\n[n,0,1,0],\n[1,0,1,1],\n[1,1,1,2],\n[n,2,1,2],\n[n,1,n,2],\n[n,0,n,1]],\n\"1\":n=>[\n[1-n,0,1,0],\n[1,0,1,1],\n[1-n,1,1,1],\n[1-n,1,1-n,2],\n[1-n,2,1,2]],\n\"2\":n=>[\n[0,0,1,0],\n[1,0,1,1],\n[0,1,1,1],\n[0,1+n,0,2],\n[1,2-n,1,2],\n[0,2,1,2]],\n\"3\":n=>[\n[0,0,1-n,0],\n[0,0,0,n],\n[1,0,1,1],\n[0,1,1,1],\n[1,1,1,2],\n[n,2,1,2]],\n\"4\":n=>[\n[0,0,0,1],\n[1,0,1-n,0],\n[1,0,1,1-n],\n[0,1,1,1],\n[1,1,1,2],\n[1-n,2,1,2]],\n\"5\": (n,maxFive)=>maxFive ? [ // 5 -> 0\n[0,0,0,1],\n[0,0,1,0],\n[n,1,1,1],\n[1,1,1,2],\n[0,2,1,2],\n[0,2,0,2],\n[1,1-n,1,1],\n[0,1,0,1+n]] : [ // 5 -> 6\n[0,0,0,1],\n[0,0,1,0],\n[0,1,1,1],\n[1,1,1,2],\n[0,2,1,2],\n[0,2-n,0,2]],\n\"6\":n=>[\n[0,0,0,1-n],\n[0,0,1,0],\n[n,1,1,1],\n[1,1-n,1,1],\n[1,1,1,2],\n[n,2,1,2],\n[0,1-n,0,2-2*n]],\n\"7\":n=>[\n[0,0,0,n],\n[0,0,1,0],\n[1,0,1,1],\n[1-n,1,1,1],\n[1,1,1,2],\n[1-n,2,1,2],\n[1-n,1,1-n,2]],\n\"8\":n=>[\n[0,0,0,1],\n[0,0,1,0],\n[1,0,1,1],\n[0,1,1,1],\n[1,1,1,2],\n[0,2,1,2],\n[0,1,0,2-n]],\n\"9\":n=>[\n[0,0,0,1],\n[0,0,1,0],\n[1,0,1,1],\n[0,1,1-n,1],\n[0,1,0,1+n],\n[1,1,1,2],\n[0,2,1,2]],\n\":\":n=>[\n[0.4,0.4,0.6,0.4],\n[0.6,0.4,0.6,0.6],\n[0.6,0.6,0.4,0.6],\n[0.4,0.4,0.4,0.6],\n[0.4,1.4,0.6,1.4],\n[0.6,1.4,0.6,1.6],\n[0.6,1.6,0.4,1.6],\n[0.4,1.4,0.4,1.6]]\n};\n\n/* Draw a transition between lastText and thisText.\n 'n' is the amount - 0..1 */\nfunction draw(lastText,thisText,n) {\n buf.clear();\n var x = 1; // x offset\n const p = 2; // padding around digits\n var y = p; // y offset\n const s = 34; // character size\n for (var i=0;i<lastText.length;i++) {\n var lastCh = lastText[i];\n var thisCh = thisText[i];\n if (thisCh==\":\") x-=4;\n var ch, chn = n;\n if (lastCh!==undefined &&\n (thisCh-1==lastCh ||\n (thisCh==0 && lastCh==5) ||\n (thisCh==0 && lastCh==9)))\n ch = lastCh;\n else {\n ch = thisCh;\n chn = 0;\n }\n var l = DIGITS[ch](chn,lastCh==5 && thisCh==0);\n l.forEach(c=>{\n if (c[0]!=c[2]) // horiz\n buf.fillRect(x+c[0]*s,y+c[1]*s-p,x+c[2]*s,y+c[3]*s+p);\n else if (c[1]!=c[3]) // vert\n buf.fillRect(x+c[0]*s-p,y+c[1]*s,x+c[2]*s+p,y+c[3]*s);\n });\n if (thisCh==\":\") x-=4;\n x+=s+p+7;\n }\n y += 2*s;\n var d = new Date();\n buf.setFont(\"6x8\");\n buf.setFontAlign(-1,-1);\n buf.drawString((\"0\"+d.getSeconds()).substr(-2), x, y-8);\n // date\n buf.setFontAlign(0,-1);\n var date = d.toString().substr(0,15);\n buf.drawString(date, buf.getWidth()/2, y+8);\n flip();\n}\n\n/* Show the current time, and animate if needed */\nfunction showTime() {\n if (!Bangle.isLCDOn()) return;\n if (animInterval) return; // in animation - quit\n var d = new Date();\n var t = (\" \"+d.getHours()).substr(-2)+\":\"+\n (\"0\"+d.getMinutes()).substr(-2);\n var l = lastTime;\n // same - don't animate\n if (t==l) {\n draw(t,l,0);\n return;\n }\n var n = 0;\n animInterval = setInterval(function() {\n n += 1/10;\n if (n>=1) {\n n=1;\n clearInterval(animInterval);\n animInterval=0;\n }\n draw(l,t,n);\n }, 20);\n lastTime = t;\n}\n\nBangle.on('lcdPower',function(on) {\n if (on) {\n showTime();\n drawWidgets();\n }\n});\n\ng.clear();\n// Update time once a second\nsetInterval(showTime, 1000);\nshowTime();\n})();\n");
require('Storage').write("*mclock",require("heatshrink").decompress(atob("mEwghC/AE8IxAAEwAWVDB4WIDBwWJAAIWPmf//8zDBpFDwYVBAAc4JJYWJDAoXKn4SC+EPAgXzC5JGCx4qDC4n//BIIEIRCEC4v/GBBdHC4xhCIw5dDC5BhCJAgXCRQoXGJAQXEUhAXHJAyNGC5KRCC7p2FC5B4CC5kggQXOBwvyBQMvSA4XL+EIwCoIC8ZHCgYXNO44LBBIiPPCAIwFC5DXGAAMwGAjvPGA4XIwYXHGALBDnAXFhCQHGAaOFwAXGPA4bFC4xIMIxIXDJBJGEC4xICSJCNEIwowEMJBdCFwwXEMJBdCC5BICDA4WDIw4wEAAMzCoMzBAgWIDAwAGCxRJEAAxFJDBgWNDBAWPAH4AYA==")));
require('Storage').write("+setting",{"name":"Settings","type":"app","icon":"*settings","src":"-settings","files":"+setting,-setting,=setting,@setting,*setting"});
require('Storage').write("-setting","Bangle.setLCDPower(1);\nBangle.setLCDTimeout(0);\n\ng.clear();\nconst storage = require('Storage');\nlet settings;\n\nfunction debug(msg, arg) {\n if (settings.debug)\n console.log(msg, arg);\n}\n\nfunction updateSettings() {\n debug('updating settings', settings);\n //storage.erase('@setting'); // - not needed, just causes extra writes if settings were the same\n storage.write('@setting', settings);\n}\n\nfunction resetSettings() {\n settings = {\n ble: false,\n dev: false,\n timeout: 10,\n vibrate: true,\n beep: true,\n timezone: 0,\n HID : false,\n HIDGestures: false,\n debug: false,\n };\n setLCDTimeout(settings.timeout);\n updateSettings();\n}\n\ntry {\n settings = storage.readJSON('@setting');\n} catch (e) {}\nif (!settings) resetSettings();\n\nconst boolFormat = (v) => v ? \"On\" : \"Off\";\n\nfunction showMainMenu() {\n const mainmenu = {\n '': { 'title': 'Settings' },\n 'BLE': {\n value: settings.ble,\n format: boolFormat,\n onchange: () => {\n settings.ble = !settings.ble;\n updateSettings();\n }\n },\n 'Programmable': {\n value: settings.dev,\n format: boolFormat,\n onchange: () => {\n settings.dev = !settings.dev;\n updateSettings();\n }\n },\n 'LCD Timeout': {\n value: settings.timeout,\n min: 0,\n max: 60,\n step: 5,\n onchange: v => {\n settings.timeout = 0 | v;\n updateSettings();\n Bangle.setLCDTimeout(settings.timeout);\n }\n },\n 'Beep': {\n value: settings.beep,\n format: boolFormat,\n onchange: () => {\n settings.beep = !settings.beep;\n updateSettings();\n if (settings.beep) {\n Bangle.beep(1);\n }\n }\n },\n 'Vibration': {\n value: settings.vibrate,\n format: boolFormat,\n onchange: () => {\n settings.vibrate = !settings.vibrate;\n updateSettings();\n if (settings.vibrate) {\n VIBRATE.write(1);\n setTimeout(()=>VIBRATE.write(0), 10);\n }\n }\n },\n 'Time Zone': {\n value: settings.timezone,\n min: -11,\n max: 12,\n step: 1,\n onchange: v => {\n settings.timezone = 0 | v;\n updateSettings();\n }\n },\n 'HID': {\n value: settings.HID,\n format: boolFormat,\n onchange: () => {\n settings.HID = !settings.HID;\n updateSettings();\n }\n },\n 'HID Gestures': {\n value: settings.HIDGestures,\n format: boolFormat,\n onchange: () => {\n settings.HIDGestures = !settings.HIDGestures;\n updateSettings();\n }\n },\n 'Debug': {\n value: settings.debug,\n format: boolFormat,\n onchange: () => {\n settings.debug = !settings.debug;\n updateSettings();\n }\n },\n 'Set Time': showSetTimeMenu,\n 'Make Connectable': makeConnectable,\n 'Reset Settings': showResetMenu,\n 'Turn Off': Bangle.off,\n '< Back': load\n };\n return Bangle.menu(mainmenu);\n}\n\nfunction showResetMenu() {\n const resetmenu = {\n '': { 'title': 'Reset' },\n '< Back': showMainMenu,\n 'Reset Settings': () => {\n E.showPrompt('Reset Settings?').then((v) => {\n if (v) {\n E.showMessage('Resetting');\n resetSettings();\n }\n setTimeout(showMainMenu, 50);\n });\n },\n // this is include for debugging. remove for production\n /*'Erase': () => {\n storage.erase('=setting');\n storage.erase('-setting');\n storage.erase('@setting');\n storage.erase('*setting');\n storage.erase('+setting');\n E.reboot();\n }*/\n };\n return Bangle.menu(resetmenu);\n}\n\nfunction makeConnectable() {\n try { NRF.wake(); } catch(e) {}\n Bluetooth.setConsole(1);\n var name=\"Bangle.js \"+NRF.getAddress().substr(-5).replace(\":\",\"\");\n E.showPrompt(name+\"\\nStay Connectable?\",{title:\"Connectable\"}).then(r=>{\n if (settings.ble!=r) {\n settings.ble = r;\n updateSettings();\n }\n if (!r) try { NRF.sleep(); } catch(e) {}\n showMainMenu();\n });\n}\n\nfunction showSetTimeMenu() {\n d = new Date();\n const timemenu = {\n '': {\n 'title': 'Set Time',\n 'predraw': function() {\n d = new Date();\n timemenu.Hour.value = d.getHours();\n timemenu.Minute.value = d.getMinutes();\n timemenu.Second.value = d.getSeconds();\n timemenu.Date.value = d.getDate();\n timemenu.Month.value = d.getMonth() + 1;\n timemenu.Year.value = d.getFullYear();\n }\n },\n '< Back': showMainMenu,\n 'Hour': {\n value: d.getHours(),\n min: 0,\n max: 23,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setHours(v);\n setTime(d.getTime()/1000);\n }\n },\n 'Minute': {\n value: d.getMinutes(),\n min: 0,\n max: 59,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setMinutes(v);\n setTime(d.getTime()/1000);\n }\n },\n 'Second': {\n value: d.getSeconds(),\n min: 0,\n max: 59,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setSeconds(v);\n setTime(d.getTime()/1000);\n }\n },\n 'Date': {\n value: d.getDate(),\n min: 1,\n max: 31,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setDate(v);\n setTime(d.getTime()/1000);\n }\n },\n 'Month': {\n value: d.getMonth() + 1,\n min: 1,\n max: 12,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setMonth(v - 1);\n setTime(d.getTime()/1000);\n }\n },\n 'Year': {\n value: d.getFullYear(),\n min: d.getFullYear() - 10,\n max: d.getFullYear() + 10,\n step: 1,\n onchange: v => {\n d = new Date();\n d.setFullYear(v);\n setTime(d.getTime()/1000);\n }\n }\n };\n return Bangle.menu(timemenu);\n}\n\nshowMainMenu();\n");
require('Storage').write("=setting","Bangle.HID = E.toUint8Array(atob(\"BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA==\"));\n\n(function() {\n var s = require('Storage').readJSON('@setting');\n var adv = { uart: true };\n if (s.ble) {\n if (s.dev)\n Bluetooth.setConsole(true);\n else\n Terminal.setConsole(true);\n if (s.HID) {\n adv.hid = Bangle.HID;\n } else\n delete Bangle.HID;\n }\n setTimeout(function() {\n NRF.setServices({}, adv);\n if (s.ble) NRF.wake();\n else NRF.sleep();\n },10);\n\n if (!s.vibrate) Bangle.buzz=()=>Promise.resolve();\n if (!s.beep) Bangle.beep=()=>Promise.resolve();\n Bangle.setLCDTimeout(s.timeout);\n if (!s.timeout) Bangle.setLCDPower(1);\n E.setTimeZone(s.timezone);\n})()\n");
require('Storage').write("@setting",{
ble: false, // Bluetooth disabled by default
dev: false, // Espruino IDE disabled by default
timeout: 10, // Default LCD timeout in seconds
vibrate: true, // Vibration enabled by default. App must support
beep: true, // Beep enabled by default. App must support
timezone: 0, // Set the timezone for the device
HID : false, // BLE HID mode, off by default
HIDGestures: false,
debug: false, // Debug mode disabled by default. App must support
});
require('Storage').write("*setting",require("heatshrink").decompress(atob("mEwghC/AFEiAAgX/C/4SFkADBgQXFBIgECAAYSCkAWGBIoXGyQTHABBZLkUhiMRiQXLIQwVBAAZlIC44tCAAYxGIxIWFGA4XIFwwwHXBAWHGAwXHFxAwGPAYXTX44XDiAJBgIXGyDAHFAYKDMAq+EGAgXNCwwX/C453XU6IWHa6ZFCC6JJCC4hgEAAoOEC5AwIFwhgEBAgwIBoqmGGBIuFVAgXFGAwLFYAoLFGIYtFeA4MGABMpC4pICkBMGBIpGFC4SuIBIoWFAAxZLC/4X/AFQ")));
require('Storage').write("+astroid",{"name":"Asteroids!","type":"app","icon":"*astroid","src":"-astroid","files":"+astroid,-astroid,*astroid"});
require('Storage').write("-astroid","Bangle.setLCDMode(\"doublebuffered\");\n\nvar W = g.getWidth();\nvar H = g.getHeight();\ng.setFontAlign(0,-1);\nvar BTNL = BTN4;\nvar BTNR = BTN5;\nvar BTNU = BTN1;\nvar BTNA = BTN2;\n\nfunction newAst(x,y) {\n var a = {\n x:x,y:y,\n vx:Math.random()-0.5,\n vy:Math.random()-0.5,\n rad:3+Math.random()*5\n };\n return a;\n}\n\nvar running = true;\nvar ship = {};\nvar ammo = [];\nvar ast = [];\nvar score = 0;\nvar level = 4;\nvar timeSinceFired = 0;\nvar lastFrame;\n\nfunction gameStop() {\n running = false;\n g.clear();\n g.drawString(\"Game Over!\",120,(H-6)/2);\n g.flip();\n}\n\nfunction addAsteroids() {\n for (var i=0;i<level;i++) {\n var d,x,y;\n do {\n x = Math.random()*W; y = Math.random()*H;\n var dx = x-ship.x, dy = y-ship.y;\n d = Math.sqrt(dx*dx+dy*dy);\n } while (d<10);\n ast.push(newAst(x,y));\n }\n}\n\nfunction gameStart() {\n ammo = [];\n ast = [];\n score = 0;\n level = 4;\n ship = { x:W/2,y:H/2,r:0,v:0 };\n timeSinceFired = 0;\n addAsteroids();\n running = true;\n}\n\n\nfunction onFrame() {\n var t = getTime();\n var d = (lastFrame===undefined)?0:(t-lastFrame)*20;\n lastFrame = t;\n\n if (!running) {\n if (BTNA.read()) gameStart();\n return;\n }\n\n if (BTNL.read()) ship.r-=0.1*d;\n if (BTNR.read()) ship.r+=0.1*d;\n ship.v *= Math.pow(0.9,d);\n if (BTNU.read()) ship.v+=0.2*d;\n ship.x += Math.cos(ship.r)*ship.v*d;\n ship.y += Math.sin(ship.r)*ship.v*d;\n if (ship.x<0) ship.x+=W;\n if (ship.y<0) ship.y+=H;\n if (ship.x>=W) ship.x-=W;\n if (ship.y>=H) ship.y-=H;\n timeSinceFired+=d;\n if (BTNA.read() && timeSinceFired>4) { // fire!\n Bangle.beep(10);\n timeSinceFired = 0;\n ammo.push({\n x:ship.x+Math.cos(ship.r)*4,\n y:ship.y+Math.sin(ship.r)*4,\n vx:Math.cos(ship.r)*3,\n vy:Math.sin(ship.r)*3,\n });\n }\n\n g.clear();\n\n g.drawString(score,120,0);\n var rs = Math.PI*0.8;\n g.drawPoly([\n ship.x+Math.cos(ship.r)*4, ship.y+Math.sin(ship.r)*4,\n ship.x+Math.cos(ship.r+rs)*3, ship.y+Math.sin(ship.r+rs)*3,\n ship.x+Math.cos(ship.r-rs)*3, ship.y+Math.sin(ship.r-rs)*3,\n ],true);\n var na = [];\n ammo.forEach(function(a) {\n a.x += a.vx*d;\n a.y += a.vy*d;\n g.fillRect(a.x-1, a.y, a.x+1, a.y);\n g.fillRect(a.x, a.y-1, a.x, a.y+1);\n var hit = false;\n ast.forEach(function(b) {\n var dx = a.x-b.x;\n var dy = a.y-b.y;\n var d = Math.sqrt(dx*dx+dy*dy);\n if (d<b.rad) {\n hit=true;\n b.hit=true;\n score++;\n }\n });\n if (!hit && a.x>=0 && a.y>=0 && a.x<W && a.y<H)\n na.push(a);\n });\n ammo=na;\n na = [];\n var crashed = false;\n ast.forEach(function(a) {\n a.x += a.vx*d;\n a.y += a.vy*d;\n g.drawCircle(a.x, a.y, a.rad);\n if (a.x<0) a.x+=W;\n if (a.y<0) a.y+=H;\n if (a.x>=W) a.x-=W;\n if (a.y>=H) a.y-=H;\n if (!a.hit) {\n na.push(a);\n } else if (a.rad>4) {\n Bangle.buzz(100);\n a.hit = false;\n var vx = 1*(Math.random()-0.5);\n var vy = 1*(Math.random()-0.5);\n a.rad/=2;\n na.push({\n x:a.x,\n y:a.y,\n vx:a.vx-vx,\n vy:a.vy-vy,\n rad:a.rad,\n });\n a.vx += vx;\n a.vy += vy;\n na.push(a);\n }\n\n var dx = a.x-ship.x;\n var dy = a.y-ship.y;\n var d = Math.sqrt(dx*dx+dy*dy);\n if (d < a.rad) crashed = true;\n });\n ast=na;\n if (!ast.length) {\n level++;\n addAsteroids();\n }\n g.flip();\n if (crashed) {\n Bangle.buzz(500);\n gameStop();\n }\n}\n\ngameStart();\nsetInterval(onFrame, 50);\n");
require('Storage').write("*astroid",require("heatshrink").decompress(atob("mEwghC/ADkN6APN7oDGC64AWDRw9DIIgXVLh/eAYQtEFxsN7oqCCQQDBC5oOBC4IDHFxgmBAY4uvGJQuMC5IuLhpdWMBQuMSBQuMF5IubhqHDFyIfGX5giFkWQGYa/KEQcCkQACmA6KFwwWDkUgNJJVGFwgABFwoXGBYIuGC4jrL8AuBmczJAgLBRhAXCFwQXGRhIXGkUjI4i/CapReHC4KEEC6a/KC48jmQXCfQoXNX44XJawx3CX5gXHXwQuJcYYXHFxaaEhIXEFxiyFGIeQFxqEIFxy0HhwuOFAgAFCxowDAAguODA4WRAH4ADA==")));
require('Storage').write("+gpstime",{"name":"GPS Time","type":"app","icon":"*gpstime","src":"-gpstime","files":"+gpstime,-gpstime,*gpstime"});
require('Storage').write("-gpstime","var img = require(\"heatshrink\").decompress(atob(\"mEwghC/AH8A1QWVhWq0AuVAAIuVAAIwT1WinQwTFwMzmQwTCYMjlUqGCIuBlWi0UzC6JdBIoMjC4UDmAuOkYXBPAWgmczLp2ilUiVAUDC4IwLFwIUBLoJ2BFwQwM1WjCgJ1DFwQwLFwJ1B0SQCkQWDGBQXBCgK9BDgKQBAAgwJOwUzRgIDBC54wCkZdGPBwACRgguDBIIwLFxEJBQIwLFxGaBYQwKFxQwLgAWGmQuBcAQwJC48ifYYwJgUidgsyC4L7DGBIXBdohnBCgL7BcYIXIGAqMCIoL7DL5IwERgIUBLoL7BO5QXBGAK7DkWiOxQXGFwOjFoUyFxZhDgBdCCgJ1CCxYxCgBABkcqOwIuNGAQXC0S9BLpgAFXoIwBmYuPAAYwCLp4wHFyYwDFyYwDFygwCCyoA/AFQA=\"));\n\nBangle.setLCDPower(1);\nBangle.setLCDTimeout(0);\n\ng.clear();\n\n\n\nvar fix;\nBangle.on('GPS',function(f) {\n fix = f;\n g.setFont(\"6x8\",2);\n g.setFontAlign(0,0);\n g.clearRect(90,30,239,90);\n if (fix.fix) {\n g.drawString(\"GPS\",170,40);\n g.drawString(\"Acquired\",170,60);\n } else {\n g.drawString(\"Waiting for\",170,40);\n g.drawString(\"GPS Fix\",170,60);\n }\n g.setFont(\"6x8\");\n g.drawString(fix.satellites+\" satellites\",170,80);\n \n g.clearRect(0,100,239,239);\n var t = fix.time.toString().split(\" \");/*\n [\n \"Sun\",\n \"Nov\",\n \"10\",\n \"2019\",\n \"15:55:35\",\n \"GMT+0100\"\n ]\n */\n //g.setFont(\"6x8\",2);\n //g.drawString(t[0],120,110); // day\n g.setFont(\"6x8\",3);\n g.drawString(t[1]+\" \"+t[2],120,135); // date\n g.setFont(\"6x8\",2);\n g.drawString(t[3],120,160); // year\n g.setFont(\"6x8\",3);\n g.drawString(t[4],120,185); // time\n // timezone\n var tz = (new Date()).getTimezoneOffset()/60;\n if (tz==0) tz=\"UTC\";\n else if (tz>0) tz=\"UTC+\"+tz;\n else tz=\"UTC\"+tz;\n g.setFont(\"6x8\",2);\n g.drawString(tz,120,210); // gmt\n g.setFontAlign(0,0,3);\n g.drawString(\"Set\",230,120);\n g.setFontAlign(0,0);\n});\n\nsetInterval(function() {\n g.drawImage(img,48,48,{scale:1.5,rotate:Math.sin(getTime()*2)/2});\n},100);\nsetWatch(function() {\n setTime(fix.time.getTime()/1000);\n}, BTN2, {repeat:true});\n\nBangle.setGPSPower(1)\n");
require('Storage').write("*gpstime",require("heatshrink").decompress(atob("mEwghC/AH8A1QWVhWq0AuVAAIuVAAIwT1WinQwTFwMzmQwTCYMjlUqGCIuBlWi0UzC6JdBIoMjC4UDmAuOkYXBPAWgmczLp2ilUiVAUDC4IwLFwIUBLoJ2BFwQwM1WjCgJ1DFwQwLFwJ1B0SQCkQWDGBQXBCgK9BDgKQBAAgwJOwUzRgIDBC54wCkZdGPBwACRgguDBIIwLFxEJBQIwLFxGaBYQwKFxQwLgAWGmQuBcAQwJC48ifYYwJgUidgsyC4L7DGBIXBdohnBCgL7BcYIXIGAqMCIoL7DL5IwERgIUBLoL7BO5QXBGAK7DkWiOxQXGFwOjFoUyFxZhDgBdCCgJ1CCxYxCgBABkcqOwIuNGAQXC0S9BLpgAFXoIwBmYuPAAYwCLp4wHFyYwDFyYwDFygwCCyoA/AFQA=")));
require('Storage').write("+compass",{"name":"Compass","type":"app","icon":"*compass","src":"-compass","files":"+compass,-compass,*compass"});
require('Storage').write("-compass","g.clear();\ng.setColor(0,0.5,1);\ng.fillCircle(120,130,80,80);\ng.setColor(0,0,0);\ng.fillCircle(120,130,70,70);\n\nfunction arrow(r,c) {\n r=r*Math.PI/180;\n var p = Math.PI/2;\n g.setColor(c);\n g.fillPoly([\n 120+60*Math.sin(r), 130-60*Math.cos(r),\n 120+10*Math.sin(r+p), 130-10*Math.cos(r+p),\n 120+10*Math.sin(r+-p), 130-10*Math.cos(r-p),\n ]);\n}\n\nvar oldHeading = 0;\nBangle.on('mag', function(m) {\n if (!Bangle.isLCDOn()) return;\n g.setFont(\"6x8\",3);\n g.setColor(0);\n g.fillRect(70,0,170,24);\n g.setColor(0xffff);\n g.setFontAlign(0,0);\n g.drawString((m.heading===undefined)?\"---\":Math.round(m.heading),120,12);\n g.setColor(0,0,0);\n arrow(oldHeading,0);\n arrow(oldHeading+180,0);\n arrow(m.heading,0xF800);\n arrow(m.heading+180,0x001F);\n oldHeading = m.heading;\n});\nBangle.setCompassPower(1);\n");
require('Storage').write("*compass",require("heatshrink").decompress(atob("mEwghC/AE8IxAAEwAWVDB4WIDBwWJAAIWOwcz///mc4DBhFDwYVBAAYYDJJAWJDAoXKCw//+YXJIwWPCQk/Aof4JBAuHC4v/GBBdHC4nzMIZGHCAIOBC4vz75hDJAgXCCgS9CC4fdAYQXGIwsyCAPyl//nvdVQoXFRofzkYXCCwJGBSIgXFQ4kymcykfdIwZgDC5XzkUyCwJGDC6FNCwPTC5i9FmQXCMgLZFC48zLgMilUv/vdkUjBII9BC6HSC55HD1WiklDNIgXIBok61QYBkSBFC5kqCwMjC6RGB1RcCR4gXIx4MC+Wqkfyl70BEQf4C4+DIwYqBC4XzGAc4C4sISAfz0QDCFgUzRwmAC4wQB+QTCC4f/AYJeCC4hIEPQi9FIwwXDbIzVHC4xICSIYXGRoRGFGAgqFXgouGC4iqDLo4XIJAQYHCwZGHGAgYBXQUzCwYuIDAwAHCxRJEAAxFJDBgWNDBAWPAH4AYA=")));
require('Storage').write("+sbt",{"name":"bluetooth","type":"widget","src":"=sbt","files":"+sbt,=sbt"});
require('Storage').write("=sbt","(function(){\nvar img_bt = E.toArrayBuffer(atob(\"CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA==\"));\nvar xpos = WIDGETPOS.tr-24;\nWIDGETPOS.tr-=24;\n\nfunction draw() {\n var x = xpos, y = 0;\n if (NRF.getSecurityStatus().connected)\n g.setColor(0,0.5,1);\n else\n g.setColor(0.3,0.3,0.3);\n g.drawImage(img_bt,10+x,2+y);\n g.setColor(1,1,1);\n}\nfunction changed() {\n draw();\n g.flip();\n}\nNRF.on('connected',changed);\nNRF.on('disconnected',changed);\nWIDGETS[\"bluetooth\"]={draw:draw};\n})()\n");
require('Storage').write("+sbat",{"name":"Battery Level","type":"widget","src":"=sbat","files":"+sbat,=sbat"});
require('Storage').write("=sbat","(function(){\nvar img_charge = E.toArrayBuffer(atob(\"DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg\"));\nvar xpos = WIDGETPOS.tr-64;\nWIDGETPOS.tr-=68;\n\nfunction draw() {\n var s = 63;\n var x = xpos, y = 0;\n g.clearRect(x,y,x+s,y+23);\n if (Bangle.isCharging()) {\n g.drawImage(img_charge,x,y);\n x+=16;\n s-=16;\n }\n g.setColor(1,1,1);\n g.fillRect(x,y+2,x+s-4,y+21);\n g.clearRect(x+2,y+4,x+s-6,y+19);\n g.fillRect(x+s-3,y+10,x+s,y+14);\n g.fillRect(x+4,y+6,x+4+E.getBattery()*(s-12)/100,y+17);\n g.setColor(1,1,1);\n}\nBangle.on('charging',function(charging) { draw(); g.flip(); if(charging)Bangle.buzz(); });\nWIDGETS[\"battery\"]={draw:draw};\n})()\n");
require('Storage').write("+funrun5",{"name":"5K Fun Run","type":"app","icon":"*funrun5","src":"-funrun5","sortorder":-1,"files":"+funrun5,-funrun5,*funrun5"});
require('Storage').write("-funrun5","var coordScale = 0.6068;\r\nvar coords = new Int32Array([-807016,6918514,-807057,6918544,-807135,6918582,-807238,6918630,-807289,6918646,-807308,6918663,-807376,6918755,-807413,6918852,-807454,6919002,-807482,6919080,-807509,6919158,-807523,6919221,-807538,6919256,-807578,6919336,-807628,6919447,-807634,6919485,-807640,6919505,-807671,6919531,-807703,6919558,-807760,6919613,-807752,6919623,-807772,6919643,-807802,6919665,-807807,6919670,-807811,6919685,-807919,6919656,-807919,6919645,-807890,6919584,-807858,6919533,-807897,6919503,-807951,6919463,-807929,6919430,-807916,6919412,-807907,6919382,-807901,6919347,-807893,6919322,-807878,6919292,-807858,6919274,-807890,6919232,-807909,6919217,-807938,6919206,-807988,6919180,-807940,6919127,-807921,6919100,-807908,6919072,-807903,6919039,-807899,6919006,-807911,6918947,-807907,6918936,-807898,6918905,-807881,6918911,-807874,6918843,-807870,6918821,-807854,6918775,-807811,6918684,-807768,6918593,-807767,6918593,-807729,6918516,-807726,6918505,-807726,6918498,-807739,6918481,-807718,6918465,-807697,6918443,-807616,6918355,-807518,6918263,-807459,6918191,-807492,6918162,-807494,6918147,-807499,6918142,-807500,6918142,-807622,6918041,-807558,6917962,-807520,6917901,-807475,6917933,-807402,6917995,-807381,6918024,-807361,6918068,-807323,6918028,-807262,6918061,-807263,6918061,-807159,6918116,-807148,6918056,-807028,6918063,-807030,6918063,-806979,6918068,-806892,6918090,-806760,6918115,-806628,6918140,-806556,6918162,-806545,6918175,-806531,6918173,-806477,6918169,-806424,6918180,-806425,6918180,-806367,6918195,-806339,6918197,-806309,6918191,-806282,6918182,-806248,6918160,-806225,6918136,-806204,6918107,-806190,6918076,-806169,6917968,-806167,6917953,-806157,6917925,-806140,6917896,-806087,6917839,-806071,6917824,-805969,6917904,-805867,6917983,-805765,6918063,-805659,6918096,-805677,6918131,-805676,6918131,-805717,6918212,-805757,6918294,-805798,6918397,-805827,6918459,-805877,6918557,-805930,6918608,-805965,6918619,-806037,6918646,-806149,6918676,-806196,6918685,-806324,6918703,-806480,6918735,-806528,6918738,-806644,6918712,-806792,6918667,-806846,6918659,-806914,6918654,-806945,6918661,-806971,6918676,-806993,6918689,-806992,6918692,-807065,6918753,-807086,6918786,-807094,6918788,-807102,6918795,-807104,6918793,-807107,6918799,-807102,6918802,-807112,6918812,-807106,6918815,-807115,6918826,-807120,6918823,-807132,6918841,-807141,6918850,-807151,6918841,-807170,6918832,-807193,6918813,-807222,6918775,-807246,6918718,-807250,6918694,-807264,6918637,-807238,6918630,-807148,6918587,-807057,6918544,-806948,6918463]);\r\n\r\nvar min = {\"x\":-807988,\"y\":6917824};\r\nvar max = {\"x\":-805659,\"y\":6919685};\r\nvar gcoords = new Uint8Array(coords.length);\r\nvar coordDistance = new Uint16Array(coords.length/2);\r\n\r\nvar PT_DISTANCE = 30; // distance to a point before we consider it complete\r\n\r\nfunction toScr(p) {\r\n return {\r\n x : 10 + (p.x-min.x)*100/(max.x-min.x),\r\n y : 230 - (p.y-min.y)*100/(max.y-min.y)\r\n };\r\n}\r\n\r\nvar last;\r\nvar totalDistance = 0;\r\nfor (var i=0;i<coords.length;i+=2) {\r\n var c = {x:coords[i],y:coords[i+1]};\r\n var s = toScr(c);\r\n gcoords[i ] = s.x;\r\n gcoords[i+1] = s.y;\r\n if (last) {\r\n var dx = c.x-last.x;\r\n var dy = c.y-last.y;\r\n totalDistance += Math.sqrt(dx*dx+dy*dy)*coordScale;\r\n coordDistance[i/2] = totalDistance;\r\n }\r\n last = c;\r\n}\r\nvar fix, lastFix;\r\nvar nextPtIdx = 0; // 2x the number of points\r\nvar nextPt = {x:coords[nextPtIdx], y:coords[nextPtIdx+1]};\r\nvar nextAngle = 0;\r\nvar nextDist = 0;\r\nvar currentDist = 0;\r\n\r\n\r\n\r\nfunction drawMap() {\r\n g.clearRect(0,0,239,120);\r\n g.setFontAlign(0,0);\r\n g.setColor(1,0,0);\r\n g.setFontVector(40);\r\n g.drawString((currentDist===undefined)?\"?\":(Math.round(currentDist)+\"m\"), 160, 30);\r\n g.setColor(1,1,1);\r\n g.setFont(\"6x8\",2);\r\n g.drawString(Math.round(totalDistance)+\"m\", 160, 70);\r\n g.drawString((nextPtIdx/2)+\"/\"+coordDistance.length, 50, 20);\r\n if (!fix.fix) {\r\n g.setColor(1,0,0);\r\n g.drawString(\"No GPS\", 50, 50);\r\n g.setFont(\"6x8\",1);\r\n g.drawString(fix.satellites+\" Sats\", 50, 70);\r\n }\r\n\r\n if (lastFix && lastFix.fix) {\r\n g.setColor(0,0,0);\r\n g.drawCircle(lastFix.s.x,lastFix.s.y,10);\r\n }\r\n for (var i=0;i<gcoords.length;i+=2) {\r\n g.setColor((i<=nextPtIdx) ? 63488 : 46486); // red/grey\r\n g.fillRect(gcoords[i]-2,gcoords[i+1]-2,gcoords[i]+2,gcoords[i+1]+2);\r\n }\r\n g.setColor(1,0,0); // first part of path\r\n g.drawPoly(new Uint8Array(gcoords.buffer, 0, nextPtIdx+2));\r\n g.setColor(1,1,1); // remaining part of path\r\n g.drawPoly(new Uint8Array(gcoords.buffer, nextPtIdx));\r\n\r\n if (fix && fix.fix) {\r\n g.setColor(1,0,0);\r\n g.drawCircle(fix.s.x,fix.s.y,10);\r\n }\r\n lastFix = fix;\r\n}\r\n\r\nfunction getNextPtInfo() {\r\n var dx = nextPt.x - fix.p.x;\r\n var dy = nextPt.y - fix.p.y;\r\n nextAngle = Math.atan2(dx,dy)*180/Math.PI;\r\n nextDist = Math.sqrt(dx*dx+dy*dy)*coordScale;\r\n}\r\n\r\nfunction onGPS(f) {\r\n fix = f;\r\n fix.p = Bangle.project(fix);\r\n fix.s = toScr(fix.p);\r\n getNextPtInfo();\r\n if ((nextDist < PT_DISTANCE) &&\r\n (nextPtIdx < coords.length)) {\r\n nextPtIdx+=2;\r\n nextPt = {x:coords[nextPtIdx], y:coords[nextPtIdx+1]};\r\n getNextPtInfo();\r\n }\r\n // work out how far we are (based on distance to next point)\r\n if (!fix.fix) {\r\n currentDist = undefined\r\n } else if (nextPtIdx+2 < coordDistance.length) {\r\n currentDist = coordDistance[1+(nextPtIdx/2)] - nextDist;\r\n } else if (nextPtIdx+2 == coordDistance.length) {\r\n currentDist = totalDistance - nextDist;\r\n } else {\r\n currentDist = totalDistance;\r\n }\r\n\r\n if (!Bangle.isLCDOn()) return;\r\n drawMap();\r\n}\r\n\r\nfunction arrow(r,c) {\r\n r=r*Math.PI/180;\r\n var p = Math.PI*3/4;\r\n g.setColor(c);\r\n g.fillPoly([\r\n 180+40*Math.sin(r), 180-40*Math.cos(r),\r\n 180+20*Math.sin(r+p), 180-20*Math.cos(r+p),\r\n 180-10*Math.sin(r), 180+10*Math.cos(r),\r\n 180+20*Math.sin(r+-p), 180-20*Math.cos(r-p),\r\n ]);\r\n}\r\n\r\nfunction onCompass(m) {\r\n if (!Bangle.isLCDOn()) return;\r\n\r\n arrow(oldHeading,0);\r\n var heading = m.heading + nextAngle;\r\n arrow(heading,0xF800);\r\n oldHeading = heading;\r\n}\r\n\r\n\r\n// draw the heading\r\nvar oldHeading = 0;\r\nBangle.on('GPS', onGPS);\r\nBangle.on('mag', onCompass);\r\nBangle.setGPSPower(1);\r\nBangle.setCompassPower(1);\r\ng.clear();\r\n");
require('Storage').write("*funrun5",require("heatshrink").decompress(atob("mEwwgurglEC6tDmYYUgkzAANAFygXKKYIADBwgXDkg8LBwwXMoQXEH4hHNC4s0O6BfECAKhDHYKnOghCB3cga6dEnYYBaScC2cznewC6W7OQU7BYyIFAAhFBAAYwGC5RFBC5QAJlY0FSIQAMkUjGgrTJRYoXFPQIXGLg8iAAJFDDgIXGgYXJGAWweQJHOC4jtBC6cidgQXUUQQXBogACDYR3HmQXHAAYzKU4IACC48kJBwFBgg7EMZYwDJAReDoh5PC4QARJAoARJAYXTJChtDoSgNAAaeEAAU0C5wqCC4q5LOYYvWgjOEaJ4AGoZGQPY6OPFw0yF34uFRlYXCFykAoQuVeIQWUAB4A=")));
require('Storage').write("+nceuwid",{"name":"nceuwid","type":"widget","src":"=nceuwid","files":"+nceuwid,=nceuwid"});
require('Storage').write("=nceuwid","(function(){\nvar img = E.toArrayBuffer(atob(\"SxgCAAAAAAAAAAAAAAAAAAAAAAAAALwDwH/gD/0B//Af+AAD4C8f/wL8Dwf/8H//C//C//AAD9C8f/wL9Dw//+H//i4AD0AH8D/C8fAAL/Dz///H//y8ALgAf/D/i8fAALrzz///H//2//PAAv/Dz28f/gLz7z///H//29VPQAv/Dx+8fqQLw/y///H//y4ALwAP/Dwv8fAALwfw//9H//i+qD8FC0DwP8fAALwPwP/4H/+C//A//AADwD8fAAAAAAC/QD+gAAAAL4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGqooBkD+AP0fgvgAAAAAAAAAAL/88C4NBw0NBjQcAAAAAAAAAALQA8C4AAyQDBjAJAAAAAAAAAALQA8C4AAzACBjAKAAAAAAAAAAL/88C4ABTACRjQbAAAAAAAAAAL/48C4AHDACRgvjAAAAAAAAAALQA8C4AcDACBgACAAAAAAAAAALQA+D0BwCQDBgANAAAAAAAAAAL/8P/wHAA0NBgAoAAAAAAAAAAGqoC+AP/0HgAQuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"));\nvar xpos = WIDGETPOS.tl;\nWIDGETPOS.tl+=75;\n\n\nWIDGETS[\"nceu\"]={draw:()=>{\n var x = xpos, y = 0;\n g.setColor(0.17,0.2,0.5);\n g.drawImage(img,x,y);\n g.setColor(1,1,1);\n}};\n})()\n");
require('Storage').write("+start",{"name":"Start","type":"app","icon":"*start","src":"-start","files":"+start,-start,*start,*bangle,*nceu,*nfr,*nodew,*tf"});
require('Storage').write("-start","NRF.sleep();\nvar g = Graphics.getInstance();\ng.setFontAlign(1, 1, 0);\nconst d = g.getWidth() - 18;\nfunction c(a) {\n return {\n width: 8,\n height: a.length,\n bpp: 1,\n buffer: (new Uint8Array(a)).buffer\n };\n}\n\nfunction welcome() {\n var welcomes = [\n 'Welcome',\n 'Failte',\n 'Bienvenue',\n 'Willkommen',\n 'Bienvenido'\n ];\n function next() {\n var n = welcomes.shift();\n E.showMessage(n);\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,116);\n welcomes.push(n);\n }\n return new Promise((res) => {\n next();\n var i = setInterval(next, 2000);\n setWatch(() => {\n clearInterval(i);\n clearWatch();\n E.showMessage('Loading...');\n res();\n }, BTN2, {repeat:false});\n });\n}\n\nfunction logos() {\n var logos = [\n ['nfr', 20, 90, ()=>{}],\n ['nceu', 20, 90, ()=>{\n g.setFont(\"6x8\", 2);\n g.setColor(0,0,1);\n g.drawString('Welcome To', 160, 110);\n g.drawString('NodeConfEU', 160, 130);\n g.drawString('2019', 200, 150);\n }],\n ['bangle', 70, 90, ()=>{}],\n ['nodew', 20, 90, ()=>{}],\n ['tf', 24, 90, ()=>{}],\n ];\n function next() {\n var n = logos.shift();\n var img = require(\"Storage\").read(\"*\"+n[0]);\n g.clear();\n g.drawImage(img, n[1], n[2]);\n n[3]();\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,116);\n logos.push(n);\n }\n return new Promise((res) => {\n next();\n var i = setInterval(next, 2000);\n setWatch(() => {\n clearInterval(i);\n clearWatch();\n res();\n }, BTN2, {repeat:false});\n });\n}\n\nfunction info() {\n var slides = [\n () => E.showMessage('Visit\\nnodewatch.dev\\nfor info'),\n () => E.showMessage('Visit\\nbanglejs.com/apps\\nfor apps'),\n () => E.showMessage('Remember\\nto charge\\nyour watch!'),\n () => {\n g.clear();\n g.setFont('6x8',2);\n g.setColor(1,1,1);\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,40);\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,194);\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,116);\n g.drawString('Menu Up', d - 50, 42);\n g.drawString('Select', d - 40, 118);\n g.drawString('Menu Down', d - 60, 196);\n },\n () => {\n g.clear();\n E.showMessage('Hold\\nto return\\nto clock');\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,194);\n },\n () => {\n g.clear();\n E.showMessage('Hold both\\nto reboot');\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,40);\n g.drawImage(c([0,8,12,14,255,14,12,8]),d,116);\n },\n () => E.showMessage('Open Settings\\nto enable\\nBluetooth')\n ];\n function next() {\n var n = slides.shift();\n n();\n slides.push(n);\n }\n return new Promise((res) => {\n next();\n var i = setInterval(next, 2000);\n setWatch(()=>{\n clearInterval(i);\n clearWatch();\n res();\n }, BTN2, {repeat:false});\n });\n}\n\nfunction cleanup() {\n E.showMessage('Loading...');\n var s = require('Storage');\n s.erase('*nfr');\n s.erase('*nceu');\n s.erase('*bangle');\n s.erase('*nodew');\n s.erase('*tf');\n s.erase('+start');\n s.erase('-start');\n s.erase('*start');\n return Promise.resolve();\n}\n\nwelcome()\n .then(logos)\n .then(info)\n .then(cleanup)\n .then(load);\n");
require('Storage').write("*start",require("heatshrink").decompress(atob("mEwxH+AHMPADQv/F+YxZYtb1wFto7SEbwwQBIsen0/ADU+jxfOjwtbAAYwDWZVWF79WfBAvEq4vfq4vIGQgviR44AEFz4vEGRQvnGA4v/F79YX9IHEq4aKh//jwvRrBcHG4ovL/4ABB5gAFRAwvVGIQveoAAIF4oABq0/CZIACF8BiBrAvTGIoaKF5AABIpVXd44AFJBQvKh4vOGBIvVL54vdX5iPhqztLoFYFpYvSh8/FxgABFpYvQRRgveoEP/8eFqAvbACi/CeA4IDP6IvUGIYGEF+EMADwvJR4ovmdoovnFoowDF8QsIF4dZF79ZF5RpCj1AFztAjy7JAAgwdFwbAFFwwAmF/4vhGFrxLFkoAvA=")));
require('Storage').write("*bangle",require("heatshrink").decompress(atob("s8wxH+AH4AQ/4AJJX5mmM/5m/AH5m/M34A/M35l/M35mqM/5m/AH5m/M34A/MqQKQJm5laOh7kNM35MGbiQxLM9osWIiZnGDI5m/VTBm/MsrOGM35maB4xm/MsoZFORZm/Fq5mDAAwUKBhAHBDJYLGAY4rOPShmRF44TIIoqlJCIxmKEZLMSBxY1GE5RTIJpwYSP5hmQZxodKLBKpIDBQZHMxS4MM1IKCMzKNQHJJmtFwbbUMy4AIM35mcJR5mbLCo1GZrxLOLZ6BMH5wOHMyAYRSRLOWGRY+MAxRmODCZeNMyLNMAA4TIBgpmPFA4YMHBZnPFIp/cADa0cC9Zm2J5YkKMtgsIGjZRTCYLMsFow0dDqJluGAgzhEJwxiAGpYLMn70hAA5N/M34A/M35mzJn5m/AH5nNJf5m/AH5m/M34A/M35m/MpgA=")));
require('Storage').write("*nceu",require("heatshrink").decompress(atob("o9HxH+AEOAwAkiIkIADIv5CEI/4/IJHbNLbPA4Iv1+JHREIwkmk2EJBBE2IoUnIwJHBCx5GoBA2DIgQACBw5G3aQQADwRG+wEmagQCBvxGufoQpDFxOCI4YNIDgxNeD4gDHCY+EwgMKBQIjGJDJlHA4YlKvzRHDRZHZDJQkMBZojVECb+OHJgkOZ6w6KCJAHJCgY1dK5wPDCg4GICYjDZBY9+vxGMArItLeRgWDwOEwmBJA5Ggv2GlMMwJGTwRFBI5JGfv2HlIACwRGRwBFDAAIUGIz+FIYMMI4R0CIxzSCRwhaMIBy2FAAaMBhmHI4QjIRqwUFIxxFJOgLTDlMGRqJHFwF+CpAWDIxgwJBgN+aoSMEIyAGBweDXBg6FABIWLAgOCw+GMhRGKByI9IIxYtQIywaJC5YTTIzwRGOyQqTIzLGNCTJGgXqIRTIzILIIzQvUI5a4EBgh6TDI7dKZJo7IAwQLFIzAjKIhwQGChBvMEhojLIqIjGBaZGPEbppOEerrLBYpGVEZrVOBpJjJIzCHNcpoqPI6gaUIywfSCLJGgXBYSZIzwRFCxoSGFSJGYCA4XLCRArQIywOJYxDPLFqA3OwFPp4HCy4lKHogAIM5uulukMIxGNy1MAAWW2JENFBJIMv8B0ksAAQQDIx2AptMpoCCChZGQGROYIocslsBIyGVIQNOp5HByhaMIxj9IAAWMIYUtRwiNPaIKNCpgUGIB4FNAAMXRq/+yhDBAAOUtJGlgKOCAAOvCJRGH2OVp1OypFGI0BHB0jUBzCMCIyAABtJEHI0RICIgYRMJBBGMCg4GICYgnPCBhHPBwQSIA5IUDGpxWOJBwgLfpgkOIhwVOEBj9WIipsKA4YiKgMBERojIIqphHAgYjKy+n1VpTJYjIADZlGEpOVlwABhTJKRL4oHFxIIEIgUKlula44/hShwIG1RFB02lJQJVII2zTC0iNBhVpI24vGgOmlpIBl2WagwWIJGFp1UKhRFGImI0FGouAaIoPIJGQMWJG5E7H5BE/I4pF/JA4kiA")));
require('Storage').write("*nfr",require("heatshrink").decompress(atob("5EuxH+AAkPABIQFABIaKDiIA/AH6qaVpwbbAH4A/YzysMDbYA/AH7GfVhbHgChrr0MT5FoTDobOQijH/Y/6aYcqzH/Y/5EeZDLHmFxTH/Y/4TVY84uJY/7H7TibHuC4rH5XmiHRZC7HpDAjSQF5QpJCgYGJY6Y8MFR4bJBSrITY9RNJb6LFNY5ALFP6CsVY55PQTzDH6MhrGPY7opYY7IZFAgqfRY9xzIWx7GQY6QsYFTTHQZDLHlL44ONDxIfJdKS3PA54qSCRL1MWpDIRY8yLNCg5FICB7ZMHZwrKaB4bQEpTHZH5bHgRhiZNbCTZSY5qBNHiDHZZCbHsOZjHPRSTHYOZbHyZDLH/Y8pQRY+zIYY8xPLG6bHsDJjHuUiTbQdTjHfQBjHYVaLHyUqbHoKJC2KCBgRDBA7HeThbHvZETHdVxKKPTkzISfJLHpZELHeOZLGOY9g8OY+TIgY74OJLqDHqFZIMJY/7HuFxRcPYJbHeXi7HUKAqGYCSgdRAH4A/XC7IdY/4A/Y9rIZY/4A/Y/7H/AH7H2ZDDH/AH7HvZC7H/SMrH/Io7IZDCoVIBgwNFBSA7JBRoZOJ5jboY6IOBY9oWKDpYLFApZkNH6YIHJ5BMNY97IZY6yvTTJCGRBwQRIExYVKB4zH+ZDDHpBQ7HgH5Q+QY/7IYY9KDJY6QeKY6xDOY/7H7BhRiPCRQGHA4SsRCJDH4ZDJqUfpQiIBR6UNDRISQOJ52TY9DIYNSyvSIZLfOAxoaIY/7HVZC4SQQBSJUC57HTDIw9QGZzH/Y7xmINyTHTAAwfKHyzH/OBTH3CRg1LYxAUFD5Y+QY9RXLLxQaWY6yIYY6g5SH57kHY9StRcbZPQQJivRC6AKJEBpGHBxrH/DcbHUEpQKQBojSPH5gpIXx7HjVp4caJkbjRGv4AkA==")));
require('Storage').write("*nodew",require("heatshrink").decompress(atob("5E1xH+AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A6hEICD4A/AH7FlY6TJ/AH7G1Y6bI/AH7FyY6rJ/AH7GyY6zI/AH7H/Y/4A/Y3DHXg5g/AH4Ak5jH/AH4A/Y9VXq5l/AH4Ag47HjZAJm/AH7GgY5S9KZBjHDZH4A/Y9S5KBxrH/AH7GkY5DGOCIrHJZA4pGBiQAPKpAQLHKQmPADRSQY6LFQCZLHPQJjIeQqwKVHTLHoEpDISY4rIGJRbH/IjBYXC67GCY5LGRY7CCaY8hEPV87Ha4zHEYyoXGY6SOKY9IQJIhRDUY+YdEY64YCAgTIBY6CDPMBxRIDpAvMIaZALV5z/NFRrHH5glGYyqOFY4LIJDJoHKaZolPMZIRMUZAyLHxotLLJzHJ4zGBY8TICY6KXJO6wdQWiJCHGRp+QJaTINYoRbQY6bICZINRY8RJQDhowPY8RMYY5YABgR9US6MHgIwGJ5QMLE44GIURY4NBSoyKIZQRObhrIMg7HkgQvIJBapSBzrBPCBhdJY5w+NeBgAFzO93rIFY8AFBxmGwydKFxSFOMJR6JFZhXLIKbHVPhbHPZALJBZA7HcAgLFBY5qFYY+KsLY/DICY4rIWC4kC/2MY6CGJOZjWPRBy8KY95MHY62ZAoLICY64/G/zGIMRxcQdB7HWBZqeQEZxcIY7e9Y4ZMHY/AwJIByrOY7JzLCJAbNY8jITCozHVURqDRDrY/MGSDHWPhTHOZAbHFZCgxHY4gxGIJbrLT6AQIDiRLQOp7ITGBbHcZB4wKY5o+IOxwWLBoQdUY54zMCJTTQBQ6GSZAjHGZCJCLY5IA/AH4AWY5L7LBpzHDNH4A/ZEDHIXQoALaZLH/AH7HsZB4WHgTHCM34A/AELHjY34A/AErHhAH4A/AEzH/AH4A/Y8xe/AH7IwCsgA/AH7IiCkYA/AH7IjCcQA/AH7JkCMAA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AHIA=")));
require('Storage').write("*tf",require("heatshrink").decompress(atob("4M7ghC/AH4A/AEcBiMQAgY+3iIACIAQhcAgYjdTzZgfYH5giYHo5BIIQGDAQYLHgMQBoZZFYAoYENGREDGgI6BAYYMDBYrXDA4RTDAobnFLgbNEYF5LFVAIGCAghsEBQYMFYAoMEC4TAxAAg5DLoqiCZQZ2CAQa2DYAiGFA4bAvXYj6DAIZkEVYizHLYhyDNoaGCL9zAEHw5aGOIwHJYAqBFL96zCHxJsEKwcBYAx5GYA4SCFobAuMohoDAQ4UCKgYCEYBR7FYGqsDIIwLFYAzUFYAhbEL+IyGIojAFBYbAEKYZYHCgghEYGoGFWoQGFJIYHBgRZDbQpsFYGiNuIP4AedooA/L/4A5gJf/AH4A/AH4A/AH4A/AH4A/AH4A/ACsN7oAJG+oJC6AoaL5QmbG7PQTLrA/YH7A/YH7AhFgxbrYA4JQFkTArWwzAlEQhnCA4bPDBQwLDHwwJH5oGBEAydNAwQHDEgggDcaJBDEY4JDJoYSEH5A7GBAbAPHg5aHCQoiSEYpNHBIxpIBIQHGTpwzGGQJlMESZCIFowTNCQLAVSZAXFGQnNL5AiNBJAeBBIYsDNJIJHTpwyMCQhGEQQwsFYo7kGAoQJDEQQyDS5ChDCgxRJGRJ4DUIpAFYBQiFJgwUGBIr3IIAy5EaJgyNcgoTGcZZCFWwxMLboxqLYBoUJGw5GIYBaSGFoo3GLApAOYCAUJQYycLYBCSHDIoUJYBfdYDwKDEwQFCBAbAfIwwHEFA6rKTpLAPEoQCDYEBgIFgzAMHwzAOXpDAkMIxALYD4wEAozAOaA7AKMIxAJVZjAWApLAOBxasGEYYZCIAyrOYCQlBYC4jGhpHCYBBpJAYSrSTp4FELQZmFYBoRDBQjAMGwvcHQYiEdBDANHgpTFApbALaYgWERpISGHYoJFYCo8JVBKAHFg5COAoY2JBI65IYBofHOYZmIYBxgGNIr4KSxJJHYCQfGCQhmIYBwjFPZDVKQg53IYCI8IBIgFIERgjEPZLVJEhHcAwUMYCo8IYBIfGAH4A/AHw")));