diff --git a/apps/android/ChangeLog b/apps/android/ChangeLog index 1e62173dc..f1107fc84 100644 --- a/apps/android/ChangeLog +++ b/apps/android/ChangeLog @@ -38,4 +38,5 @@ 0.36: Move from wrapper function to {} and let - faster execution at boot Allow `calendar-` to take an array of items to remove 0.37: Support Gadgetbridge canned responses -0.38: Don't rewrite settings file on every boot! \ No newline at end of file +0.38: Don't rewrite settings file on every boot! +0.39: Move GB message handling into a library to reduce boot time from 40ms->13ms \ No newline at end of file diff --git a/apps/android/boot.js b/apps/android/boot.js index 53cf51ff2..18297d84f 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -1,349 +1,24 @@ /* global GB */ { - let gbSend = function(message) { - Bluetooth.println(""); - Bluetooth.println(JSON.stringify(message)); - } - let lastMsg; // for music messages - may not be needed now... - let actInterval; // Realtime activity reporting interval when `act` is true - let actHRMHandler; // For Realtime activity reporting - let gpsState = {}; // keep information on GPS via Gadgetbridge - - // this settings var is deleted after this executes to save memory + // settings var is deleted after this executes to save memory let settings = Object.assign({rp:true,as:true,vibrate:".."}, require("Storage").readJSON("android.settings.json",1)||{} ); let _GB = global.GB; - let fetchRecInterval; - global.GB = (event) => { + global.GB = e => { // feed a copy to other handlers if there were any - if (_GB) setTimeout(_GB,0,Object.assign({},event)); - - /* TODO: Call handling, fitness */ - var HANDLERS = { - // {t:"notify",id:int, src,title,subject,body,sender,tel:string} add - "notify" : function() { - Object.assign(event,{t:"add",positive:true, negative:true}); - // Detect a weird GadgetBridge bug and fix it - // For some reason SMS messages send two GB notifications, with different sets of info - if (lastMsg && event.body == lastMsg.body && lastMsg.src == undefined && event.src == "Messages") { - // Mutate the other message - event.id = lastMsg.id; - } - lastMsg = event; - require("messages").pushMessage(event); - }, - // {t:"notify~",id:int, title:string} // modified - "notify~" : function() { event.t="modify";require("messages").pushMessage(event); }, - // {t:"notify-",id:int} // remove - "notify-" : function() { event.t="remove";require("messages").pushMessage(event); }, - // {t:"find", n:bool} // find my phone - "find" : function() { - if (Bangle.findDeviceInterval) { - clearInterval(Bangle.findDeviceInterval); - delete Bangle.findDeviceInterval; - } - if (event.n) // Ignore quiet mode: we always want to find our watch - Bangle.findDeviceInterval = setInterval(_=>Bangle.buzz(),1000); - }, - // {t:"musicstate", state:"play/pause",position,shuffle,repeat} - "musicstate" : function() { - require("messages").pushMessage({t:"modify",id:"music",title:"Music",state:event.state}); - }, - // {t:"musicinfo", artist,album,track,dur,c(track count),n(track num} - "musicinfo" : function() { - require("messages").pushMessage(Object.assign(event, {t:"modify",id:"music",title:"Music"})); - }, - // {"t":"call","cmd":"incoming/end","name":"Bob","number":"12421312"}) - "call" : function() { - Object.assign(event, { - t:event.cmd=="incoming"?"add":"remove", - id:"call", src:"Phone", - positive:true, negative:true, - title:event.name||/*LANG*/"Call", body:/*LANG*/"Incoming call\n"+event.number}); - require("messages").pushMessage(event); - }, - "canned_responses_sync" : function() { - require("Storage").writeJSON("replies.json", event.d); - }, - // {"t":"alarm", "d":[{h:int,m:int,rep:int},... } - "alarm" : function() { - //wipe existing GB alarms - var sched; - try { sched = require("sched"); } catch (e) {} - if (!sched) return; // alarms may not be installed - var gbalarms = sched.getAlarms().filter(a=>a.appid=="gbalarms"); - for (var i = 0; i < gbalarms.length; i++) - sched.setAlarm(gbalarms[i].id, undefined); - var alarms = sched.getAlarms(); - var time = new Date(); - var currentTime = time.getHours() * 3600000 + - time.getMinutes() * 60000 + - time.getSeconds() * 1000; - for (var j = 0; j < event.d.length; j++) { - // prevents all alarms from going off at once?? - var dow = event.d[j].rep; - var rp = false; - if (!dow) { - dow = 127; //if no DOW selected, set alarm to all DOW - } else { - rp = true; - } - var last = (event.d[j].h * 3600000 + event.d[j].m * 60000 < currentTime) ? (new Date()).getDate() : 0; - var a = require("sched").newDefaultAlarm(); - a.id = "gb"+j; - a.appid = "gbalarms"; - a.on = event.d[j].on !== undefined ? event.d[j].on : true; - a.t = event.d[j].h * 3600000 + event.d[j].m * 60000; - a.dow = ((dow&63)<<1) | (dow>>6); // Gadgetbridge sends DOW in a different format - a.rp = rp; - a.last = last; - alarms.push(a); - } - sched.setAlarms(alarms); - sched.reload(); - }, - //TODO perhaps move those in a library (like messages), used also for viewing events? - //add and remove events based on activity on phone (pebble-like) - // {t:"calendar", id:int, type:int, timestamp:seconds, durationInSeconds, title:string, description:string,location:string,calName:string.color:int,allDay:bool - "calendar" : function() { - var cal = require("Storage").readJSON("android.calendar.json",true); - if (!cal || !Array.isArray(cal)) cal = []; - var i = cal.findIndex(e=>e.id==event.id); - if(i<0) - cal.push(event); - else - cal[i] = event; - require("Storage").writeJSON("android.calendar.json", cal); - }, - // {t:"calendar-", id:int} - "calendar-" : function() { - var cal = require("Storage").readJSON("android.calendar.json",true); - //if any of those happen we are out of sync! - if (!cal || !Array.isArray(cal)) cal = []; - if (Array.isArray(event.id)) - cal = cal.filter(e=>!event.id.includes(e.id)); - else - cal = cal.filter(e=>e.id!=event.id); - require("Storage").writeJSON("android.calendar.json", cal); - }, - //triggered by GB, send all ids - // { t:"force_calendar_sync_start" } - "force_calendar_sync_start" : function() { - var cal = require("Storage").readJSON("android.calendar.json",true); - if (!cal || !Array.isArray(cal)) cal = []; - gbSend({t:"force_calendar_sync", ids: cal.map(e=>e.id)}); - }, - // {t:"http",resp:"......",[id:"..."]} - "http":function() { - //get the promise and call the promise resolve - if (Bangle.httpRequest === undefined) return; - var request=Bangle.httpRequest[event.id]; - if (request === undefined) return; //already timedout or wrong id - delete Bangle.httpRequest[event.id]; - clearTimeout(request.t); //t = timeout variable - if(event.err!==undefined) //if is error - request.j(event.err); //r = reJect function - else - request.r(event); //r = resolve function - }, - // {t:"gps", lat, lon, alt, speed, course, time, satellites, hdop, externalSource:true } - "gps": function() { - if (!settings.overwriteGps) return; - // modify event for using it as Bangle GPS event - delete event.t; - if (!isFinite(event.satellites)) event.satellites = NaN; - if (!isFinite(event.course)) event.course = NaN; - event.fix = 1; - if (event.long!==undefined) { // for earlier Gadgetbridge implementations - event.lon = event.long; - delete event.long; - } - if (event.time){ - event.time = new Date(event.time); - } - - if (!gpsState.lastGPSEvent) { - // this is the first event, save time of arrival and deactivate internal GPS - Bangle.moveGPSPower(0); - } else { - // this is the second event, store the intervall for expecting the next GPS event - gpsState.interval = Date.now() - gpsState.lastGPSEvent; - } - gpsState.lastGPSEvent = Date.now(); - // in any case, cleanup the GPS state in case no new events arrive - if (gpsState.timeoutGPS) clearTimeout(gpsState.timeoutGPS); - gpsState.timeoutGPS = setTimeout(()=>{ - // reset state - gpsState.lastGPSEvent = undefined; - gpsState.timeoutGPS = undefined; - gpsState.interval = undefined; - // did not get an expected GPS event but have GPS clients, switch back to internal GPS - if (Bangle.isGPSOn()) Bangle.moveGPSPower(1); - }, (gpsState.interval || 10000) + 1000); - Bangle.emit('GPS', event); - }, - // {t:"is_gps_active"} - "is_gps_active": function() { - gbSend({ t: "gps_power", status: Bangle.isGPSOn() }); - }, - // {t:"act", hrm:bool, stp:bool, int:int} - "act": function() { - if (actInterval) clearInterval(actInterval); - actInterval = undefined; - if (actHRMHandler) - actHRMHandler = undefined; - Bangle.setHRMPower(event.hrm,"androidact"); - if (!(event.hrm || event.stp)) return; - if (!isFinite(event.int)) event.int=1; - var lastSteps = Bangle.getStepCount(); - var lastBPM = 0; - actHRMHandler = function(e) { - lastBPM = e.bpm; - }; - Bangle.on('HRM',actHRMHandler); - actInterval = setInterval(function() { - var steps = Bangle.getStepCount(); - gbSend({ t: "act", stp: steps-lastSteps, hrm: lastBPM, rt:1 }); - lastSteps = steps; - }, event.int*1000); - }, - // {t:"actfetch", ts:long} - "actfetch": function() { - gbSend({t: "actfetch", state: "start"}); - var actCount = 0; - var actCb = function(r) { - // The health lib saves the samples at the start of the 10-minute block - // However, GB expects them at the end of the block, so let's offset them - // here to keep a consistent API in the health lib - var sampleTs = r.date.getTime() + 600000; - if (sampleTs >= event.ts) { - gbSend({ - t: "act", - ts: sampleTs, - stp: r.steps, - hrm: r.bpm, - mov: r.movement - }); - actCount++; - } - } - if (event.ts != 0) { - require("health").readAllRecordsSince(new Date(event.ts - 600000), actCb); - } else { - require("health").readFullDatabase(actCb); - } - gbSend({t: "actfetch", state: "end", count: actCount}); - }, - //{t:"listRecs", id:"20230616a"} - "listRecs": function() { - let recs = require("Storage").list(/^recorder\.log.*\.csv$/,{sf:true}).map(s => s.slice(12, 21)); - if (event.id.length > 2) { // Handle if there was no id supplied. Then we send a list all available recorder logs back. - let firstNonsyncedIdx = recs.findIndex((logId) => logId > event.id); - if (-1 == firstNonsyncedIdx) { - recs = [] - } else { - recs = recs.slice(firstNonsyncedIdx); - } - } - gbSend({t:"actTrksList", list: recs}); // TODO: split up in multiple transmissions? - }, - //{t:"fetchRec", id:"20230616a"} - "fetchRec": function() { - // TODO: Decide on what names keys should have. - if (fetchRecInterval) { - clearInterval(fetchRecInterval); - fetchRecInterval = undefined; - } - if (event.id=="stop") { - return - } else { - let log = require("Storage").open("recorder.log"+event.id+".csv","r"); - let lines = "init";// = log.readLine(); - let pkgcnt = 0; - gbSend({t:"actTrk", log:event.id, lines:"erase", cnt:pkgcnt}); // "erase" will prompt Gadgetbridge to erase the contents of a already fetched log so we can rewrite it without keeping lines from the previous (probably failed) fetch. - let sendlines = ()=>{ - lines = log.readLine(); - for (var i = 0; i < 3; i++) { - let line = log.readLine(); - if (line) lines += line; - } - pkgcnt++; - gbSend({t:"actTrk", log:event.id, lines:lines, cnt:pkgcnt}); - if (!lines && fetchRecInterval) { - clearInterval(fetchRecInterval); - fetchRecInterval = undefined; - } - } - fetchRecInterval = setInterval(sendlines, 50) - } - }, - "nav": function() { - event.id="nav"; - if (event.instr) { - event.t="add"; - event.src="maps"; // for the icon - event.title="Navigation"; - if (require("messages").getMessages().find(m=>m.id=="nav")) - event.t = "modify"; - } else { - event.t="remove"; - } - require("messages").pushMessage(event); - }, - "cards" : function() { - // we receive all, just override what we have - if (Array.isArray(event.d)) - require("Storage").writeJSON("android.cards.json", event.d); - }, - "accelsender": function () { - require("Storage").writeJSON("accelsender.json", {enabled: event.enable, interval: event.interval}); - load(); - } - }; - var h = HANDLERS[event.t]; - if (h) h(); else console.log("GB Unknown",event); + if (_GB) setTimeout(_GB,0,Object.assign({},e)); + Bangle.emit("GB",e); + require("android").gbHandler(e); }; // HTTP request handling - see the readme - // options = {id,timeout,xpath} - Bangle.http = (url,options)=>{ - options = options||{}; - if (!NRF.getSecurityStatus().connected) - return Promise.reject(/*LANG*/"Not connected to Bluetooth"); - if (Bangle.httpRequest === undefined) - Bangle.httpRequest={}; - if (options.id === undefined) { - // try and create a unique ID - do { - options.id = Math.random().toString().substr(2); - } while( Bangle.httpRequest[options.id]!==undefined); - } - //send the request - var req = {t: "http", url:url, id:options.id}; - if (options.xpath) req.xpath = options.xpath; - if (options.return) req.return = options.return; // for xpath - if (options.method) req.method = options.method; - if (options.body) req.body = options.body; - if (options.headers) req.headers = options.headers; - gbSend(req); - //create the promise - var promise = new Promise(function(resolve,reject) { - //save the resolve function in the dictionary and create a timeout (30 seconds default) - Bangle.httpRequest[options.id]={r:resolve,j:reject,t:setTimeout(()=>{ - //if after "timeoutMillisec" it still hasn't answered -> reject - delete Bangle.httpRequest[options.id]; - reject("Timeout"); - },options.timeout||30000)}; - }); - return promise; - }; - + Bangle.http = (url,options)=>require("android").httpHandler(url,options); // Battery monitor - let sendBattery = function() { gbSend({ t: "status", bat: E.getBattery(), chg: Bangle.isCharging()?1:0 }); } + let sendBattery = function() { require("android").gbSend({ t: "status", bat: E.getBattery(), chg: Bangle.isCharging()?1:0 }); } Bangle.on("charging", sendBattery); NRF.on("connect", () => setTimeout(function() { sendBattery(); - gbSend({t: "ver", fw: process.env.VERSION, hw: process.env.HWVERSION}); + require("android").gbSend({t: "ver", fw: process.env.VERSION, hw: process.env.HWVERSION}); GB({t:"force_calendar_sync_start"}); // send a list of our calendar entries to start off the sync process }, 2000)); NRF.on("disconnect", () => { @@ -357,81 +32,24 @@ setInterval(sendBattery, 10*60*1000); // Health tracking - if 'realtime' data is sent with 'rt:1', but let's still send our activity log every 10 mins Bangle.on('health', h=>{ - gbSend({ t: "act", stp: h.steps, hrm: h.bpm, mov: h.movement }); + require("android").gbSend({ t: "act", stp: h.steps, hrm: h.bpm, mov: h.movement }); }); // Music control Bangle.musicControl = cmd => { // play/pause/next/previous/volumeup/volumedown - gbSend({ t: "music", n:cmd }); + require("android").gbSend({ t: "music", n:cmd }); }; // Message response Bangle.messageResponse = (msg,response) => { - if (msg.id=="call") return gbSend({ t: "call", n:response?"ACCEPT":"REJECT" }); - if (isFinite(msg.id)) return gbSend({ t: "notify", n:response?"OPEN":"DISMISS", id: msg.id }); + if (msg.id=="call") return require("android").gbSend({ t: "call", n:response?"ACCEPT":"REJECT" }); + if (isFinite(msg.id)) return require("android").gbSend({ t: "notify", n:response?"OPEN":"DISMISS", id: msg.id }); // error/warn here? }; Bangle.messageIgnore = msg => { - if (isFinite(msg.id)) return gbSend({ t: "notify", n:"MUTE", id: msg.id }); + if (isFinite(msg.id)) return require("android").gbSend({ t: "notify", n:"MUTE", id: msg.id }); }; // GPS overwrite logic - if (settings.overwriteGps) { // if the overwrite option is set.. - const origSetGPSPower = Bangle.setGPSPower; - Bangle.moveGPSPower = (state) => { - if (Bangle.isGPSOn()){ - let orig = Bangle._PWR.GPS; - delete Bangle._PWR.GPS; - origSetGPSPower(state); - Bangle._PWR.GPS = orig; - } - }; - - // work around Serial1 for GPS not working when connected to something - let serialTimeout; - let wrap = function(f){ - return (s)=>{ - if (serialTimeout) clearTimeout(serialTimeout); - origSetGPSPower(1, "androidgpsserial"); - f(s); - serialTimeout = setTimeout(()=>{ - serialTimeout = undefined; - origSetGPSPower(0, "androidgpsserial"); - }, 10000); - }; - }; - Serial1.println = wrap(Serial1.println); - Serial1.write = wrap(Serial1.write); - - // replace set GPS power logic to suppress activation of gps (and instead request it from the phone) - Bangle.setGPSPower = ((isOn, appID) => { - let pwr; - if (!this.lastGPSEvent){ - // use internal GPS power function if no gps event has arrived from GadgetBridge - pwr = origSetGPSPower(isOn, appID); - } else { - // we are currently expecting the next GPS event from GadgetBridge, keep track of GPS state per app - if (!Bangle._PWR) Bangle._PWR={}; - if (!Bangle._PWR.GPS) Bangle._PWR.GPS=[]; - if (!appID) appID="?"; - if (isOn && !Bangle._PWR.GPS.includes(appID)) Bangle._PWR.GPS.push(appID); - if (!isOn && Bangle._PWR.GPS.includes(appID)) Bangle._PWR.GPS.splice(Bangle._PWR.GPS.indexOf(appID),1); - pwr = Bangle._PWR.GPS.length>0; - // stop internal GPS, no clients left - if (!pwr) origSetGPSPower(0); - } - // always update Gadgetbridge on current power state - gbSend({ t: "gps_power", status: pwr }); - return pwr; - }).bind(gpsState); - // allow checking for GPS via GadgetBridge - Bangle.isGPSOn = () => { - return !!(Bangle._PWR && Bangle._PWR.GPS && Bangle._PWR.GPS.length>0); - }; - // stop GPS on boot if not activated - setTimeout(()=>{ - if (!Bangle.isGPSOn()) gbSend({ t: "gps_power", status: false }); - },3000); - } - + if (settings.overwriteGps) require("android").overwriteGPS(); // remove settings object so it's not taking up RAM delete settings; } diff --git a/apps/android/lib.js b/apps/android/lib.js new file mode 100644 index 000000000..71d7f6043 --- /dev/null +++ b/apps/android/lib.js @@ -0,0 +1,388 @@ +exports.gbSend = function(message) { + Bluetooth.println(""); + Bluetooth.println(JSON.stringify(message)); +} +let lastMsg, // for music messages - may not be needed now... + gpsState = {}, // keep information on GPS via Gadgetbridge + settings = Object.assign({rp:true,as:true,vibrate:".."}, + require("Storage").readJSON("android.settings.json",1)||{} + ); + +exports.gbHandler = (event) => { + var HANDLERS = { + // {t:"notify",id:int, src,title,subject,body,sender,tel:string} add + "notify" : function() { + print("notify",event); + Object.assign(event,{t:"add",positive:true, negative:true}); + // Detect a weird GadgetBridge bug and fix it + // For some reason SMS messages send two GB notifications, with different sets of info + if (lastMsg && event.body == lastMsg.body && lastMsg.src == undefined && event.src == "Messages") { + // Mutate the other message + event.id = lastMsg.id; + } + lastMsg = event; + require("messages").pushMessage(event); + }, + // {t:"notify~",id:int, title:string} // modified + "notify~" : function() { event.t="modify";require("messages").pushMessage(event); }, + // {t:"notify-",id:int} // remove + "notify-" : function() { event.t="remove";require("messages").pushMessage(event); }, + // {t:"find", n:bool} // find my phone + "find" : function() { + if (Bangle.findDeviceInterval) { + clearInterval(Bangle.findDeviceInterval); + delete Bangle.findDeviceInterval; + } + if (event.n) // Ignore quiet mode: we always want to find our watch + Bangle.findDeviceInterval = setInterval(_=>Bangle.buzz(),1000); + }, + // {t:"musicstate", state:"play/pause",position,shuffle,repeat} + "musicstate" : function() { + require("messages").pushMessage({t:"modify",id:"music",title:"Music",state:event.state}); + }, + // {t:"musicinfo", artist,album,track,dur,c(track count),n(track num} + "musicinfo" : function() { + require("messages").pushMessage(Object.assign(event, {t:"modify",id:"music",title:"Music"})); + }, + // {"t":"call","cmd":"incoming/end","name":"Bob","number":"12421312"}) + "call" : function() { + Object.assign(event, { + t:event.cmd=="incoming"?"add":"remove", + id:"call", src:"Phone", + positive:true, negative:true, + title:event.name||/*LANG*/"Call", body:/*LANG*/"Incoming call\n"+event.number}); + require("messages").pushMessage(event); + }, + "canned_responses_sync" : function() { + require("Storage").writeJSON("replies.json", event.d); + }, + // {"t":"alarm", "d":[{h:int,m:int,rep:int},... } + "alarm" : function() { + //wipe existing GB alarms + var sched; + try { sched = require("sched"); } catch (e) {} + if (!sched) return; // alarms may not be installed + var gbalarms = sched.getAlarms().filter(a=>a.appid=="gbalarms"); + for (var i = 0; i < gbalarms.length; i++) + sched.setAlarm(gbalarms[i].id, undefined); + var alarms = sched.getAlarms(); + var time = new Date(); + var currentTime = time.getHours() * 3600000 + + time.getMinutes() * 60000 + + time.getSeconds() * 1000; + for (var j = 0; j < event.d.length; j++) { + // prevents all alarms from going off at once?? + var dow = event.d[j].rep; + var rp = false; + if (!dow) { + dow = 127; //if no DOW selected, set alarm to all DOW + } else { + rp = true; + } + var last = (event.d[j].h * 3600000 + event.d[j].m * 60000 < currentTime) ? (new Date()).getDate() : 0; + var a = require("sched").newDefaultAlarm(); + a.id = "gb"+j; + a.appid = "gbalarms"; + a.on = event.d[j].on !== undefined ? event.d[j].on : true; + a.t = event.d[j].h * 3600000 + event.d[j].m * 60000; + a.dow = ((dow&63)<<1) | (dow>>6); // Gadgetbridge sends DOW in a different format + a.rp = rp; + a.last = last; + alarms.push(a); + } + sched.setAlarms(alarms); + sched.reload(); + }, + //TODO perhaps move those in a library (like messages), used also for viewing events? + //add and remove events based on activity on phone (pebble-like) + // {t:"calendar", id:int, type:int, timestamp:seconds, durationInSeconds, title:string, description:string,location:string,calName:string.color:int,allDay:bool + "calendar" : function() { + var cal = require("Storage").readJSON("android.calendar.json",true); + if (!cal || !Array.isArray(cal)) cal = []; + var i = cal.findIndex(e=>e.id==event.id); + if(i<0) + cal.push(event); + else + cal[i] = event; + require("Storage").writeJSON("android.calendar.json", cal); + }, + // {t:"calendar-", id:int} + "calendar-" : function() { + var cal = require("Storage").readJSON("android.calendar.json",true); + //if any of those happen we are out of sync! + if (!cal || !Array.isArray(cal)) cal = []; + if (Array.isArray(event.id)) + cal = cal.filter(e=>!event.id.includes(e.id)); + else + cal = cal.filter(e=>e.id!=event.id); + require("Storage").writeJSON("android.calendar.json", cal); + }, + //triggered by GB, send all ids + // { t:"force_calendar_sync_start" } + "force_calendar_sync_start" : function() { + var cal = require("Storage").readJSON("android.calendar.json",true); + if (!cal || !Array.isArray(cal)) cal = []; + exports.gbSend({t:"force_calendar_sync", ids: cal.map(e=>e.id)}); + }, + // {t:"http",resp:"......",[id:"..."]} + "http":function() { + //get the promise and call the promise resolve + if (Bangle.httpRequest === undefined) return; + var request=Bangle.httpRequest[event.id]; + if (request === undefined) return; //already timedout or wrong id + delete Bangle.httpRequest[event.id]; + clearTimeout(request.t); //t = timeout variable + if(event.err!==undefined) //if is error + request.j(event.err); //r = reJect function + else + request.r(event); //r = resolve function + }, + // {t:"gps", lat, lon, alt, speed, course, time, satellites, hdop, externalSource:true } + "gps": function() { + if (!settings.overwriteGps) return; + // modify event for using it as Bangle GPS event + delete event.t; + if (!isFinite(event.satellites)) event.satellites = NaN; + if (!isFinite(event.course)) event.course = NaN; + event.fix = 1; + if (event.long!==undefined) { // for earlier Gadgetbridge implementations + event.lon = event.long; + delete event.long; + } + if (event.time){ + event.time = new Date(event.time); + } + + if (!gpsState.lastGPSEvent) { + // this is the first event, save time of arrival and deactivate internal GPS + Bangle.moveGPSPower(0); + } else { + // this is the second event, store the intervall for expecting the next GPS event + gpsState.interval = Date.now() - gpsState.lastGPSEvent; + } + gpsState.lastGPSEvent = Date.now(); + // in any case, cleanup the GPS state in case no new events arrive + if (gpsState.timeoutGPS) clearTimeout(gpsState.timeoutGPS); + gpsState.timeoutGPS = setTimeout(()=>{ + // reset state + gpsState.lastGPSEvent = undefined; + gpsState.timeoutGPS = undefined; + gpsState.interval = undefined; + // did not get an expected GPS event but have GPS clients, switch back to internal GPS + if (Bangle.isGPSOn()) Bangle.moveGPSPower(1); + }, (gpsState.interval || 10000) + 1000); + Bangle.emit('GPS', event); + }, + // {t:"is_gps_active"} + "is_gps_active": function() { + exports.gbSend({ t: "gps_power", status: Bangle.isGPSOn() }); + }, + // {t:"act", hrm:bool, stp:bool, int:int} + "act": function() { + if (exports.actInterval) clearInterval(exports.actInterval); + exports.actInterval = undefined; + if (exports.actHRMHandler) + exports.actHRMHandler = undefined; + Bangle.setHRMPower(event.hrm,"androidact"); + if (!(event.hrm || event.stp)) return; + if (!isFinite(event.int)) event.int=1; + var lastSteps = Bangle.getStepCount(); + var lastBPM = 0; + exports.actHRMHandler = function(e) { + lastBPM = e.bpm; + }; + Bangle.on('HRM',exports.actHRMHandler); + exports.actInterval = setInterval(function() { + var steps = Bangle.getStepCount(); + exports.gbSend({ t: "act", stp: steps-lastSteps, hrm: lastBPM, rt:1 }); + lastSteps = steps; + }, event.int*1000); + }, + // {t:"actfetch", ts:long} + "actfetch": function() { + exports.gbSend({t: "actfetch", state: "start"}); + var actCount = 0; + var actCb = function(r) { + // The health lib saves the samples at the start of the 10-minute block + // However, GB expects them at the end of the block, so let's offset them + // here to keep a consistent API in the health lib + var sampleTs = r.date.getTime() + 600000; + if (sampleTs >= event.ts) { + exports.gbSend({ + t: "act", + ts: sampleTs, + stp: r.steps, + hrm: r.bpm, + mov: r.movement + }); + actCount++; + } + } + if (event.ts != 0) { + require("health").readAllRecordsSince(new Date(event.ts - 600000), actCb); + } else { + require("health").readFullDatabase(actCb); + } + exports.gbSend({t: "actfetch", state: "end", count: actCount}); + }, + //{t:"listRecs", id:"20230616a"} + "listRecs": function() { + let recs = require("Storage").list(/^recorder\.log.*\.csv$/,{sf:true}).map(s => s.slice(12, 21)); + if (event.id.length > 2) { // Handle if there was no id supplied. Then we send a list all available recorder logs back. + let firstNonsyncedIdx = recs.findIndex((logId) => logId > event.id); + if (-1 == firstNonsyncedIdx) { + recs = [] + } else { + recs = recs.slice(firstNonsyncedIdx); + } + } + exports.gbSend({t:"actTrksList", list: recs}); // TODO: split up in multiple transmissions? + }, + //{t:"fetchRec", id:"20230616a"} + "fetchRec": function() { + // TODO: Decide on what names keys should have. + if (exports.fetchRecInterval) { + clearInterval(exports.fetchRecInterval); + exports.fetchRecInterval = undefined; + } + if (event.id=="stop") { + return; + } else { + let log = require("Storage").open("recorder.log"+event.id+".csv","r"); + let lines = "init";// = log.readLine(); + let pkgcnt = 0; + exports.gbSend({t:"actTrk", log:event.id, lines:"erase", cnt:pkgcnt}); // "erase" will prompt Gadgetbridge to erase the contents of a already fetched log so we can rewrite it without keeping lines from the previous (probably failed) fetch. + let sendlines = ()=>{ + lines = log.readLine(); + for (var i = 0; i < 3; i++) { + let line = log.readLine(); + if (line) lines += line; + } + pkgcnt++; + exports.gbSend({t:"actTrk", log:event.id, lines:lines, cnt:pkgcnt}); + if (!lines && exports.fetchRecInterval) { + clearInterval(exports.fetchRecInterval); + exports.fetchRecInterval = undefined; + } + }; + exports.fetchRecInterval = setInterval(sendlines, 50); + } + }, + "nav": function() { + event.id="nav"; + if (event.instr) { + event.t="add"; + event.src="maps"; // for the icon + event.title="Navigation"; + if (require("messages").getMessages().find(m=>m.id=="nav")) + event.t = "modify"; + } else { + event.t="remove"; + } + require("messages").pushMessage(event); + }, + "cards" : function() { + // we receive all, just override what we have + if (Array.isArray(event.d)) + require("Storage").writeJSON("android.cards.json", event.d); + }, + "accelsender": function () { + require("Storage").writeJSON("accelsender.json", {enabled: event.enable, interval: event.interval}); + load(); + } + }; + var h = HANDLERS[event.t]; + if (h) h(); else console.log("GB Unknown",event); +}; + +// HTTP request handling - see the readme +// options = {id,timeout,xpath} +exports.httpHandler = (url,options) => { + options = options||{}; + if (!NRF.getSecurityStatus().connected) + return Promise.reject(/*LANG*/"Not connected to Bluetooth"); + if (Bangle.httpRequest === undefined) + Bangle.httpRequest={}; + if (options.id === undefined) { + // try and create a unique ID + do { + options.id = Math.random().toString().substr(2); + } while( Bangle.httpRequest[options.id]!==undefined); + } + //send the request + var req = {t: "http", url:url, id:options.id}; + if (options.xpath) req.xpath = options.xpath; + if (options.return) req.return = options.return; // for xpath + if (options.method) req.method = options.method; + if (options.body) req.body = options.body; + if (options.headers) req.headers = options.headers; + exports.gbSend(req); + //create the promise + var promise = new Promise(function(resolve,reject) { + //save the resolve function in the dictionary and create a timeout (30 seconds default) + Bangle.httpRequest[options.id]={r:resolve,j:reject,t:setTimeout(()=>{ + //if after "timeoutMillisec" it still hasn't answered -> reject + delete Bangle.httpRequest[options.id]; + reject("Timeout"); + },options.timeout||30000)}; + }); + return promise; +}; + +exports.overwriteGPS = () => { // if the overwrite option is set, call this on init.. + const origSetGPSPower = Bangle.setGPSPower; + Bangle.moveGPSPower = (state) => { + if (Bangle.isGPSOn()){ + let orig = Bangle._PWR.GPS; + delete Bangle._PWR.GPS; + origSetGPSPower(state); + Bangle._PWR.GPS = orig; + } + }; + + // work around Serial1 for GPS not working when connected to something + let serialTimeout; + let wrap = function(f){ + return (s)=>{ + if (serialTimeout) clearTimeout(serialTimeout); + origSetGPSPower(1, "androidgpsserial"); + f(s); + serialTimeout = setTimeout(()=>{ + serialTimeout = undefined; + origSetGPSPower(0, "androidgpsserial"); + }, 10000); + }; + }; + Serial1.println = wrap(Serial1.println); + Serial1.write = wrap(Serial1.write); + + // replace set GPS power logic to suppress activation of gps (and instead request it from the phone) + Bangle.setGPSPower = ((isOn, appID) => { + let pwr; + if (!this.lastGPSEvent){ + // use internal GPS power function if no gps event has arrived from GadgetBridge + pwr = origSetGPSPower(isOn, appID); + } else { + // we are currently expecting the next GPS event from GadgetBridge, keep track of GPS state per app + if (!Bangle._PWR) Bangle._PWR={}; + if (!Bangle._PWR.GPS) Bangle._PWR.GPS=[]; + if (!appID) appID="?"; + if (isOn && !Bangle._PWR.GPS.includes(appID)) Bangle._PWR.GPS.push(appID); + if (!isOn && Bangle._PWR.GPS.includes(appID)) Bangle._PWR.GPS.splice(Bangle._PWR.GPS.indexOf(appID),1); + pwr = Bangle._PWR.GPS.length>0; + // stop internal GPS, no clients left + if (!pwr) origSetGPSPower(0); + } + // always update Gadgetbridge on current power state + require("android").gbSend({ t: "gps_power", status: pwr }); + return pwr; + }).bind(gpsState); + // allow checking for GPS via GadgetBridge + Bangle.isGPSOn = () => { + return !!(Bangle._PWR && Bangle._PWR.GPS && Bangle._PWR.GPS.length>0); + }; + // stop GPS on boot if not activated + setTimeout(()=>{ + if (!Bangle.isGPSOn()) require("android").gbSend({ t: "gps_power", status: false }); + },3000); +}; \ No newline at end of file diff --git a/apps/android/metadata.json b/apps/android/metadata.json index b1c3ecfaa..584c071cf 100644 --- a/apps/android/metadata.json +++ b/apps/android/metadata.json @@ -2,7 +2,7 @@ "id": "android", "name": "Android Integration", "shortName": "Android", - "version": "0.38", + "version": "0.39", "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", "icon": "app.png", "tags": "tool,system,messages,notifications,gadgetbridge", @@ -13,7 +13,8 @@ {"name":"android.app.js","url":"app.js"}, {"name":"android.settings.js","url":"settings.js"}, {"name":"android.img","url":"app-icon.js","evaluate":true}, - {"name":"android.boot.js","url":"boot.js"} + {"name":"android.boot.js","url":"boot.js"}, + {"name":"android","url":"lib.js"} ], "data": [{"name":"android.settings.json"}, {"name":"android.calendar.json"}, {"name":"android.cards.json"}], "sortorder": -8 diff --git a/apps/assistedgps/ChangeLog b/apps/assistedgps/ChangeLog index 13f928f18..89b1c80f8 100644 --- a/apps/assistedgps/ChangeLog +++ b/apps/assistedgps/ChangeLog @@ -3,4 +3,5 @@ 0.03: Select GNSS systems to use for Bangle.js 2 0.04: Now turns GPS off after upload 0.05: Fix regression in 0.04 that caused AGPS data not to get loaded -0.06: Auto-set GPS output sentences - newer Bangle.js 2 don't include RMC (GPS direction + time) by default \ No newline at end of file +0.06: Auto-set GPS output sentences - newer Bangle.js 2 don't include RMC (GPS direction + time) by default +0.07: Bangle.js 2 now gets estimated time + lat/lon from the browser (~3x faster fix) \ No newline at end of file diff --git a/apps/assistedgps/custom.html b/apps/assistedgps/custom.html index 994f6d053..a51219346 100644 --- a/apps/assistedgps/custom.html +++ b/apps/assistedgps/custom.html @@ -60,6 +60,7 @@ diff --git a/apps/assistedgps/metadata.json b/apps/assistedgps/metadata.json index 8d4e07fa3..73f775a72 100644 --- a/apps/assistedgps/metadata.json +++ b/apps/assistedgps/metadata.json @@ -2,7 +2,7 @@ "id": "assistedgps", "name": "Assisted GPS Updater (AGPS)", "shortName": "AGPS", - "version": "0.06", + "version": "0.07", "description": "Downloads assisted GPS (AGPS) data to Bangle.js for faster GPS startup and more accurate fixes. **No app will be installed**, this just uploads new data to the GPS chip.", "sortorder": -1, "icon": "app.png", diff --git a/apps/banglebridge/ChangeLog b/apps/banglebridge/ChangeLog index 62542be60..a4b22db22 100644 --- a/apps/banglebridge/ChangeLog +++ b/apps/banglebridge/ChangeLog @@ -1,2 +1,3 @@ 0.01: New app! 0.02: Minor code improvements +0.03: Remove clearing of the screen (will break running apps) and fix lint errors \ No newline at end of file diff --git a/apps/banglebridge/metadata.json b/apps/banglebridge/metadata.json index 86e1face0..1dbb2e1de 100644 --- a/apps/banglebridge/metadata.json +++ b/apps/banglebridge/metadata.json @@ -2,8 +2,8 @@ "id": "banglebridge", "name": "BangleBridge", "shortName": "BangleBridge", - "version": "0.02", - "description": "Widget that allows Bangle Js to record pair and end data using Bluetooth Low Energy in combination with the BangleBridge Android App", + "version": "0.03", + "description": "Widget that allows Bangle.js to record pair and end data using Bluetooth Low Energy in combination with the BangleBridge Android App (**Note:** this has nothing to do with Gadgetbridge)", "icon": "widget.png", "type": "widget", "tags": "widget", diff --git a/apps/banglebridge/widget.js b/apps/banglebridge/widget.js index 692822b39..c805b0f39 100644 --- a/apps/banglebridge/widget.js +++ b/apps/banglebridge/widget.js @@ -1,10 +1,10 @@ (() => { /** * Widget measurements - * Description: + * Description: * name: connection.wid.js *icon: conectionIcon.icon - * + * */ //Font @@ -24,7 +24,7 @@ //Sensors code /** - * + * * @author Jorge */ function accel() { @@ -35,8 +35,7 @@ }); setInterval(function () { - - acclS = accelN.x + "##" + accelN.y + "##" + accelN.z + "\n" + accelN.diff + "##" + accelN.mag; + //acclS = accelN.x + "##" + accelN.y + "##" + accelN.z + "\n" + accelN.diff + "##" + accelN.mag; data[3] = accelN; }, 2 * 1000); @@ -45,8 +44,7 @@ function btt() { setInterval(function () { - - bttS = E.getBattery(); //return String + //bttS = E.getBattery(); //return String data[2] = E.getBattery(); }, 15 * 1000); @@ -65,9 +63,9 @@ setInterval(function () { - compssS = "A: " + compssN.x + " ## " + compssN.y + " ## " + compssN.z + "\n" + + /*compssS = "A: " + compssN.x + " ## " + compssN.y + " ## " + compssN.z + "\n" + "B: " + compssN.dx + " ## " + compssN.dy + " ## " + compssN.dz + " ## " + "\n" + - "C: " + compssN.heading; //return String + "C: " + compssN.heading; *///return String data[4] = compssN; }, 2 * 1000); @@ -86,8 +84,8 @@ setInterval(function () { - gpsS = "A: " + gpsN.lat + " ## " + gpsN.lon + " ## " + gpsN.alt + "\n" + "B: " + gpsN.speed + " ## " + gpsN.course + " ## " + gpsN.time + "\n" + - "C: " + gpsN.satellites + " ## " + gpsN.fix; //return String + /*gpsS = "A: " + gpsN.lat + " ## " + gpsN.lon + " ## " + gpsN.alt + "\n" + "B: " + gpsN.speed + " ## " + gpsN.course + " ## " + gpsN.time + "\n" + + "C: " + gpsN.satellites + " ## " + gpsN.fix; *///return String // work out how to display the current time var d = new Date(); var year = d.getFullYear(); @@ -150,7 +148,7 @@ //console.log("Index ==> "+ index); msr[indexFinal] = nueva; - item = nueva; + //item = nueva; lastInsert = indexFinal; } @@ -180,7 +178,7 @@ hrmN = normalize(hrmN); var roundedRate = parseFloat(hrmN).toFixed(2); - hrmS = String.valueOf(roundedRate); //return String + //hrmS = String.valueOf(roundedRate); //return String //console.log("array----->" + msr); data[0] = roundedRate; @@ -205,7 +203,7 @@ setInterval(function () { - stepS = String.valueOf(stepN); //return String + //stepS = String.valueOf(stepN); //return String data[1] = stepN; }, 2 * 1000); @@ -240,12 +238,11 @@ g.setFont("Vector", 45); g.drawString(prueba,100,200);*/ if (flip == 1) { //when off - + flip = 0; //Bangle.buzz(1000); - g.clear(); } else { //when on - + flip = 1; g.setFont("Vector", 30); g.drawString(data[0], 65, 180); @@ -283,7 +280,7 @@ com: data[4], gps: data[5] }; - /* g.clear(); + /* g.drawString(compssS,100,200); */ @@ -293,7 +290,7 @@ //draw(); }, 5 * 1000); - + WIDGETS["banglebridge"]={ area: "tl", width: 10, diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 1d8e44b72..5b0fcc583 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -72,3 +72,7 @@ 0.61: Instead of breaking execution with an Exception when updating boot, just use if..else (fix 'Uncaught undefined') 0.62: Handle setting for configuring BLE privacy 0.63: Only set BLE `display:1` if we have a passkey +0.64: Automatically create .widcache and .clkinfocache to speed up loads + Bangle.loadWidgets overwritten with fast version on success + Refuse to work on firmware <2v16 and remove old polyfills +0.65: Only display interpreter errors if log is nonzero \ No newline at end of file diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js index aa4a7e7b5..07d8d2031 100644 --- a/apps/boot/bootupdate.js +++ b/apps/boot/bootupdate.js @@ -12,14 +12,13 @@ if (DEBUG) { boot += "var _tm=Date.now()\n"; bootPost += "delete _tm;"; } -if (require('Storage').hash) { // new in 2v11 - helps ensure files haven't changed - let CRC = E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\.boot\.js/)+E.CRC32(process.env.GIT_COMMIT); - boot += `if(E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\\.boot\\.js/)+E.CRC32(process.env.GIT_COMMIT)!=${CRC})`; -} else { - let CRC = E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/))+E.CRC32(process.env.GIT_COMMIT); - boot += `if(E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\\.boot\\.js/))+E.CRC32(process.env.GIT_COMMIT)!=${CRC})`; +if (FWVERSION < 216) { + E.showMessage(/*LANG*/"Please update Bangle.js firmware\n\nCurrent = "+process.env.VERSION,{title:"ERROR"}); + throw new Error("Old firmware"); } -boot += `{eval(require('Storage').read('bootupdate.js'));print("Storage Updated!")}else{\n`; +let CRC = E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\.js$/)+E.CRC32(process.env.GIT_COMMIT); +boot += `if(E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\\.js$/)+E.CRC32(process.env.GIT_COMMIT)!=${CRC})`; +boot += `{eval(require('Storage').read('bootupdate.js'));}else{\n`; boot += `E.setFlags({pretokenise:1});\n`; boot += `var bleServices = {}, bleServiceOptions = { uart : true};\n`; bootPost += `NRF.setServices(bleServices,bleServiceOptions);delete bleServices,bleServiceOptions;\n`; // executed after other boot code @@ -44,7 +43,7 @@ LoopbackA.setConsole(true);\n`; boot += ` Bluetooth.line=""; Bluetooth.on('data',function(d) { - var l = (Bluetooth.line + d).split(/[\\n\\r]/); + let l = (Bluetooth.line + d).split(/[\\n\\r]/); Bluetooth.line = l.pop(); l.forEach(n=>Bluetooth.emit("line",n)); }); @@ -67,12 +66,12 @@ if (s.ble===false) boot += `if (!NRF.getSecurityStatus().connected) NRF.sleep(); if (s.timeout!==undefined) boot += `Bangle.setLCDTimeout(${s.timeout});\n`; if (!s.timeout) boot += `Bangle.setLCDPower(1);\n`; boot += `E.setTimeZone(${s.timezone});`; -// Draw out of memory errors onto the screen -boot += `E.on('errorFlag', function(errorFlags) { +// Draw out of memory errors onto the screen if logging enabled +if (s.log) boot += `E.on('errorFlag', function(errorFlags) { g.reset(1).setColor("#ff0000").setFont("6x8").setFontAlign(0,1).drawString(errorFlags,g.getWidth()/2,g.getHeight()-1).flip(); print("Interpreter error:", errorFlags); - E.getErrorFlags(); // clear flags so we get called next time -});\n`; + E.getErrorFlags(); +});\n`;// E.getErrorFlags() -> clear flags so we get called next time // stop users doing bad things! if (global.save) boot += `global.save = function() { throw new Error("You can't use save() on Bangle.js without overwriting the bootloader!"); }\n`; // Apply any settings-specific stuff @@ -86,30 +85,18 @@ if (s.bleprivacy || (s.passkey!==undefined && s.passkey.length==6)) { if (s.blename === false) boot+=`NRF.setAdvertising({},{showName:false});\n`; if (s.whitelist && !s.whitelist_disabled) boot+=`NRF.on('connect', function(addr) { if (!NRF.ignoreWhitelist) { let whitelist = (require('Storage').readJSON('setting.json',1)||{}).whitelist; if (NRF.resolveAddress !== undefined) { let resolvedAddr = NRF.resolveAddress(addr); if (resolvedAddr !== undefined) addr = resolvedAddr + " (resolved)"; } if (!whitelist.includes(addr)) NRF.disconnect(); }});\n`; if (s.rotate) boot+=`g.setRotation(${s.rotate&3},${s.rotate>>2});\n` // screen rotation +boot+=`Bangle.loadWidgets=function(){if(!global.WIDGETS)eval(require("Storage").read(".widcache"))};\n`; // ================================================== FIXING OLDER FIRMWARES -if (FWVERSION<215.068) // 2v15.68 and before had compass heading inverted. - boot += `Bangle.on('mag',e=>{if(!isNaN(e.heading))e.heading=360-e.heading;}); -Bangle.getCompass=(c=>(()=>{e=c();if(!isNaN(e.heading))e.heading=360-e.heading;return e;}))(Bangle.getCompass);`; - // deleting stops us getting confused by our own decl. builtins can't be deleted // this is a polyfill without fastloading capability delete Bangle.showClock; if (!Bangle.showClock) boot += `Bangle.showClock = ()=>{load(".bootcde")};\n`; delete Bangle.load; if (!Bangle.load) boot += `Bangle.load = load;\n`; -let date = new Date(); -delete date.toLocalISOString; // toLocalISOString was only introduced in 2v15 -if (!date.toLocalISOString) boot += `Date.prototype.toLocalISOString = function() { - var o = this.getTimezoneOffset(); - var d = new Date(this.getTime() - o*60000); - var sign = o>0?"-":"+"; - o = Math.abs(o); - return d.toISOString().slice(0,-1)+sign+Math.floor(o/60).toString().padStart(2,0)+(o%60).toString().padStart(2,0); -};\n`; // show timings if (DEBUG) boot += `print(".boot0",0|(Date.now()-_tm),"ms");_tm=Date.now();\n` -// ================================================== BOOT.JS +// ================================================== .BOOT0 // Append *.boot.js files. // Name files with a number - eg 'foo.5.boot.js' to enforce order (lowest first). Numbered files get placed before non-numbered // These could change bleServices/bleServiceOptions if needed @@ -128,17 +115,47 @@ let bootFiles = require('Storage').list(/\.boot\.js$/).sort((a,b)=>{ }); // precalculate file size bootPost += "}"; -let fileSize = boot.length + bootPost.length; -bootFiles.forEach(bootFile=>{ - // match the size of data we're adding below in bootFiles.forEach - if (DEBUG) fileSize += 2+bootFile.length+1; // `//${bootFile}\n` comment - fileSize += require('Storage').read(bootFile).length+2; // boot code plus ";\n" - if (DEBUG) fileSize += 48+E.toJS(bootFile).length; // `print(${E.toJS(bootFile)},0|(Date.now()-_tm),"ms");_tm=Date.now();\n` -}); -// write file in chunks (so as not to use up all RAM) -require('Storage').write('.boot0',boot,0,fileSize); -let fileOffset = boot.length; -bootFiles.forEach(bootFile=>{ +let fileOffset,fileSize; +/* code to output a file, plus preable and postable +when called with dst==undefined it just increments +fileOffset so we can see ho wbig the file has to be */ +let outputFile = (dst,src,pre,post) => {"ram"; + if (DEBUG) { + if (dst) require('Storage').write(dst,`//${src}\n`,fileOffset); + fileOffset+=2+src.length+1; + } + if (pre) { + if (dst) require('Storage').write(dst,pre,fileOffset); + fileOffset+=pre.length; + } + let f = require('Storage').read(src); + if (src.endsWith("clkinfo.js") && f[0]!="(") { + /* we shouldn't have to do this but it seems sometimes (sched 0.28) folks have + used libraries which get added into the clockinfo, and we can't use them directly + to we have to revert back to eval */ + f = `eval(require('Storage').read(${E.toJS(src)}))`; + } + if (dst) { + // we can't just write 'f' in one go because it can be too big + let len = f.length; + let offset = 0; + while (len) { + let chunk = Math.min(len, 2048); + require('Storage').write(dst,f.substr(offset, chunk),fileOffset); + fileOffset+=chunk; + offset+=chunk; + len-=chunk; + } + } else + fileOffset+=f.length; + if (dst) require('Storage').write(dst,post,fileOffset); + fileOffset+=post.length; + if (DEBUG) { + if (dst) require('Storage').write(dst,`print(${E.toJS(src)},0|(Date.now()-_tm),"ms");_tm=Date.now();\n`,fileOffset); + fileOffset += 48+E.toJS(src).length; + } +}; +let outputFileComplete = (dst,fn) => { // we add a semicolon so if the file is wrapped in (function(){ ... }() // with no semicolon we don't end up with (function(){ ... }()(function(){ ... }() // which would cause an error! @@ -146,31 +163,48 @@ bootFiles.forEach(bootFile=>{ // "//"+bootFile+"\n"+require('Storage').read(bootFile)+";\n"; // but we need to do this without ever loading everything into RAM as some // boot files seem to be getting pretty big now. - if (DEBUG) { - require('Storage').write('.boot0',`//${bootFile}\n`,fileOffset); - fileOffset+=2+bootFile.length+1; - } - let bf = require('Storage').read(bootFile); - // we can't just write 'bf' in one go because at least in 2v13 and earlier - // Espruino wants to read the whole file into RAM first, and on Bangle.js 1 - // it can be too big (especially BTHRM). - let bflen = bf.length; - let bfoffset = 0; - while (bflen) { - let bfchunk = Math.min(bflen, 2048); - require('Storage').write('.boot0',bf.substr(bfoffset, bfchunk),fileOffset); - fileOffset+=bfchunk; - bfoffset+=bfchunk; - bflen-=bfchunk; - } - require('Storage').write('.boot0',";\n",fileOffset); - fileOffset+=2; - if (DEBUG) { - require('Storage').write('.boot0',`print(${E.toJS(bootFile)},0|(Date.now()-_tm),"ms");_tm=Date.now();\n`,fileOffset); - fileOffset += 48+E.toJS(bootFile).length - } -}); + outputFile(dst,fn,"",";\n"); +}; +fileOffset = boot.length + bootPost.length; +bootFiles.forEach(fn=>outputFileComplete(undefined,fn)); // just get sizes +fileSize = fileOffset; +require('Storage').write('.boot0',boot,0,fileSize); +fileOffset = boot.length; +bootFiles.forEach(fn=>outputFileComplete('.boot0',fn)); require('Storage').write('.boot0',bootPost,fileOffset); +delete boot,bootPost,bootFiles; +// ================================================== .WIDCACHE for widgets +let widgetFiles = require("Storage").list(/\.wid\.js$/); +let widget = `// Made by bootupdate.js\nglobal.WIDGETS={};`, widgetPost = `var W=WIDGETS;WIDGETS={}; +Object.keys(W).sort((a,b)=>(0|W[b].sortorder)-(0|W[a].sortorder)).forEach(k=>WIDGETS[k]=W[k]);`; // sort +if (DEBUG) widget+="var _tm=Date.now();"; +outputFileComplete = (dst,fn) => { + outputFile(dst,fn,"try{",`}catch(e){print(${E.toJS(fn)},e,e.stack)}\n`); +}; +fileOffset = widget.length + widgetPost.length; +widgetFiles.forEach(fn=>outputFileComplete(undefined,fn)); // just get sizes +fileSize = fileOffset; +require('Storage').write('.widcache',widget,0,fileSize); +fileOffset = widget.length; +widgetFiles.forEach(fn=>outputFileComplete('.widcache',fn)); +require('Storage').write('.widcache',widgetPost,fileOffset); +delete widget,widgetPost,widgetFiles; +// ================================================== .clkinfocache for clockinfos +let ciFiles = require("Storage").list(/\.clkinfo\.js$/); +let ci = `// Made by bootupdate.js\n`; +if (DEBUG) ci+="var _tm=Date.now();"; +outputFileComplete = (dst,fn) => { + outputFile(dst,fn,"try{let fn=",`;let a=fn(),b=menu.find(x=>x.name===a.name);if(b)b.items=b.items.concat(a.items)else menu=menu.concat(a);}catch(e){print(${E.toJS(fn)},e,e.stack)}\n`); +}; +fileOffset = ci.length; +ciFiles.forEach(fn=>outputFileComplete(undefined,fn)); // just get sizes +fileSize = fileOffset; +require('Storage').write('.clkinfocache',ci,0,fileSize); +fileOffset = ci.length; +ciFiles.forEach(fn=>outputFileComplete('.clkinfocache',fn)); +delete ci,ciFiles; +// test with require("clock_info").load() +// ================================================== END E.showMessage(/*LANG*/"Reloading..."); } // .bootcde should be run automatically after if required, since diff --git a/apps/boot/metadata.json b/apps/boot/metadata.json index dcc55da58..afe576e71 100644 --- a/apps/boot/metadata.json +++ b/apps/boot/metadata.json @@ -1,7 +1,7 @@ { "id": "boot", "name": "Bootloader", - "version": "0.63", + "version": "0.65", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "icon": "bootloader.png", "type": "bootloader", @@ -11,6 +11,9 @@ {"name":".boot0","url":"boot0.js"}, {"name":".bootcde","url":"bootloader.js"}, {"name":"bootupdate.js","url":"bootupdate.js"} + ],"data": [ + {"name":".widcache"}, + {"name":".clkinfocache"} ], "sortorder": -10 } diff --git a/apps/clock_info/ChangeLog b/apps/clock_info/ChangeLog index 8276321ac..7d2043899 100644 --- a/apps/clock_info/ChangeLog +++ b/apps/clock_info/ChangeLog @@ -10,4 +10,6 @@ 0.09: Save clkinfo settings on kill and remove 0.10: Fix focus bug when changing focus between two clock infos 0.11: Prepend swipe listener if possible -0.12: Add drawFilledImage to allow drawing icons with a separately coloured middle \ No newline at end of file +0.12: Add drawFilledImage to allow drawing icons with a separately coloured middle +0.13: Cache loaded ClockInfos so if we have clockInfoWidget and a clock, we don't load them twice (saves ~300ms) +0.14: Check for .clkinfocache and use that if exists (from boot 0.64) \ No newline at end of file diff --git a/apps/clock_info/lib.js b/apps/clock_info/lib.js index a9ca7de31..0e20ab855 100644 --- a/apps/clock_info/lib.js +++ b/apps/clock_info/lib.js @@ -14,6 +14,8 @@ if (stepGoal == undefined) { exports.loadCount = 0; /// A list of all the instances returned by addInteractive exports.clockInfos = []; +/// A list of loaded clockInfos +exports.clockInfoMenus = undefined; /// Load the settings, with defaults exports.loadSettings = function() { @@ -29,6 +31,8 @@ exports.loadSettings = function() { /// Load a list of ClockInfos - this does not cache and reloads each time exports.load = function() { + if (exports.clockInfoMenus) + return exports.clockInfoMenus; var settings = exports.loadSettings(); delete settings.apps; // keep just the basic settings in memory // info used for drawing... @@ -131,10 +135,14 @@ exports.load = function() { hide : function() { clearInterval(this.interval); delete this.interval; }, }); } - + var clkInfoCache = require('Storage').read('.clkinfocache'); + if (clkInfoCache!==undefined) { + // note: code below is included in clkinfocache by bootupdate.js + // we use clkinfocache if it exists as it's faster + eval(clkInfoCache); + } else require("Storage").list(/clkinfo\.js$/).forEach(fn => { // In case there exists already a menu object b with the same name as the next // object a, we append the items. Otherwise we add the new object a to the list. - require("Storage").list(/clkinfo.js$/).forEach(fn => { try{ var a = eval(require("Storage").read(fn))(); var b = menu.find(x => x.name === a.name); @@ -146,6 +154,7 @@ exports.load = function() { }); // return it all! + exports.clockInfoMenus = menu; return menu; }; @@ -345,6 +354,9 @@ exports.addInteractive = function(menu, options) { menuHideItem(menu[options.menuA].items[options.menuB]); exports.loadCount--; delete exports.clockInfos[options.index]; + // If nothing loaded now, clear our list of loaded menus + if (exports.loadCount==0) + exports.clockInfoMenus = undefined; }; options.redraw = function() { drawItem(menu[options.menuA].items[options.menuB]); diff --git a/apps/clock_info/metadata.json b/apps/clock_info/metadata.json index 3d47c5062..1d9a73ce3 100644 --- a/apps/clock_info/metadata.json +++ b/apps/clock_info/metadata.json @@ -1,7 +1,7 @@ { "id": "clock_info", "name": "Clock Info Module", "shortName": "Clock Info", - "version":"0.12", + "version":"0.14", "description": "A library used by clocks to provide extra information on the clock face (Altitude, BPM, etc)", "icon": "app.png", "type": "module", diff --git a/apps/clockbg/ChangeLog b/apps/clockbg/ChangeLog index 3c681a638..a370befc0 100644 --- a/apps/clockbg/ChangeLog +++ b/apps/clockbg/ChangeLog @@ -4,4 +4,5 @@ 0.04: More options for different background colors 'Plasma' generative background Add a 'view' option in settings menu to view the current background -0.05: Random square+plasma speed improvements (~2x faster) \ No newline at end of file +0.05: Random square+plasma speed improvements (~2x faster) +0.06: 25% speed improvement if Math.randInt exists (2v25 fw) \ No newline at end of file diff --git a/apps/clockbg/lib.js b/apps/clockbg/lib.js index 59345340f..256f2f372 100644 --- a/apps/clockbg/lib.js +++ b/apps/clockbg/lib.js @@ -1,6 +1,7 @@ let settings; exports.reload = function() { + //let t = Date.now(); settings = Object.assign({ style : "randomcolor", colors : ["#F00","#0F0","#00F"] @@ -17,7 +18,8 @@ exports.reload = function() { let bpp = (settings.colors.length>4)?4:2; let bg = Graphics.createArrayBuffer(11,11,bpp,{msb:true}); let u32 = new Uint32Array(bg.buffer); // faster to do 1/4 of the ops of E.mapInPlace(bg.buffer, bg.buffer, ()=>Math.random()*256); - E.mapInPlace(u32, u32, function(r,n){"ram";return r()*n}.bind(null,Math.random,0x100000000)); // random pixels + if (Math.randInt) E.mapInPlace(u32, u32, Math.randInt); // random pixels + else E.mapInPlace(u32, u32, function(r,n){"ram";return r()*n}.bind(null,Math.random,0x100000000)); // random pixels bg.buffer[bg.buffer.length-1]=Math.random()*256; // 11x11 isn't a multiple of 4 bytes - we need to set the last one! bg.palette = new Uint16Array(1<g.toColor(c))); @@ -28,7 +30,8 @@ exports.reload = function() { settings.style = "image"; let bg = Graphics.createArrayBuffer(16,16,4,{msb:true}); let u32 = new Uint32Array(bg.buffer); // faster to do 1/4 of the ops of E.mapInPlace(bg.buffer, bg.buffer, ()=>Math.random()*256); - E.mapInPlace(u32, u32, function(r,n){"ram";return r()*n}.bind(null,Math.random,0x100000000)); // random pixels + if (Math.randInt) E.mapInPlace(u32, u32, Math.randInt); // random pixels + else E.mapInPlace(u32, u32, function(r,n){"ram";return r()*n}.bind(null,Math.random,0x100000000)); // random pixels bg.filter([ // a gaussian filter to smooth out 1, 4, 7, 4, 1, 4,16,26,16, 4, @@ -42,6 +45,7 @@ exports.reload = function() { settings.imgOpt = {scale:11}; delete settings.colors; } + //console.log("bg",Date.now()-t); }; exports.reload(); diff --git a/apps/clockbg/metadata.json b/apps/clockbg/metadata.json index 85b1f8a5a..ba6fb6712 100644 --- a/apps/clockbg/metadata.json +++ b/apps/clockbg/metadata.json @@ -1,7 +1,7 @@ { "id": "clockbg", "name": "Clock Backgrounds", "shortName":"Backgrounds", - "version": "0.05", + "version": "0.06", "description": "Library that allows clocks to include a custom background (generated on demand or uploaded).", "icon": "app.png", "screenshots": [{"url":"screenshot.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"}], diff --git a/apps/hworldclock/ChangeLog b/apps/hworldclock/ChangeLog index 42e785b0a..ad327831a 100644 --- a/apps/hworldclock/ChangeLog +++ b/apps/hworldclock/ChangeLog @@ -21,3 +21,4 @@ 0.34: Fix 'fast load' so clock doesn't always redraw when screen unlocked/locked 0.35: Minor code improvements 0.36: Minor code improvements +0.37: Fix settings (show default as '90' not 'off') \ No newline at end of file diff --git a/apps/hworldclock/metadata.json b/apps/hworldclock/metadata.json index 422ef6b89..aeae2d254 100644 --- a/apps/hworldclock/metadata.json +++ b/apps/hworldclock/metadata.json @@ -2,7 +2,7 @@ "id": "hworldclock", "name": "Hanks World Clock", "shortName": "Hanks World Clock", - "version": "0.36", + "version": "0.37", "description": "Current time zone plus up to three others", "allow_emulator":true, "icon": "app.png", diff --git a/apps/hworldclock/settings.js b/apps/hworldclock/settings.js index 98b91dc7b..457bc47b3 100644 --- a/apps/hworldclock/settings.js +++ b/apps/hworldclock/settings.js @@ -2,6 +2,7 @@ var FILE = "hworldclock.json"; var settings = Object.assign({ secondsOnUnlock: false, + rotationTarget: "90", }, require('Storage').readJSON(FILE, true) || {}); function writeSettings() { @@ -55,4 +56,4 @@ E.showMenu(mainmenu); -}); +}) \ No newline at end of file diff --git a/apps/lint_exemptions.js b/apps/lint_exemptions.js index b5c6bc640..3bcbf6fd3 100644 --- a/apps/lint_exemptions.js +++ b/apps/lint_exemptions.js @@ -515,12 +515,6 @@ module.exports = { "no-undef" ] }, - "apps/widbt_notify/widget.js": { - "hash": "16372ffcbc6bd1419ca326c7da40c2195f82a4bfceb6f123c15872624c4f0adf", - "rules": [ - "no-undef" - ] - }, "apps/widbgjs/widget.js": { "hash": "9852ce9aafb0a1ca3029d497282c8cdf07438ea36a3323313bad5b7569b1081b", "rules": [ @@ -1157,12 +1151,6 @@ module.exports = { "no-undef" ] }, - "apps/banglebridge/widget.js": { - "hash": "4ee8d6749e1d0e28c58ad871fd9f6ccbca2d716bb4fbd3511ba4c34a6a5897e1", - "rules": [ - "no-undef" - ] - }, "apps/bad/bad.app.js": { "hash": "d1354613102818190dd4e6e28fd715db7dc4d51b8e618cae61a3135529cc97eb", "rules": [ diff --git a/apps/locale/locales.js b/apps/locale/locales.js index 7e4105f3d..c704e0f90 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -177,7 +177,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d. %b %Y", "1": "%d.%m.%Y" }, // 1. Mär 2020 // 01.03.20 abmonth: "Jan,Feb,Mär,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez", @@ -194,7 +194,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%Y/%m/%d", 1: "%y/%m/%d" }, abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", @@ -210,7 +210,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d %b %Y", 1: "%d-%m-%Y" }, // 28 feb 2020 // 28-02-2020 abday: "zo,ma,di,wo,do,vr,za", @@ -258,7 +258,7 @@ var locales = { speed: "km/h", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d %B %Y", "1": "%d/%m/%Y" }, // 1 mars 2020 // 01/03/2020 abmonth: "janv,févr,mars,avril,mai,juin,juil,août,sept,oct,nov,déc", @@ -290,7 +290,7 @@ var locales = { speed: 'km/h', distance: { "0": "m", "1": "km" }, temperature: '°C', - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%B %d %Y", "1": "%Y-%m-%d" }, // March 1 2020 // 2020-03-01 abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", @@ -306,7 +306,7 @@ var locales = { speed: "km/t", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d. %b. %Y", 1: "%d/%m %Y" }, // 1. feb. 2020 // 01/02 2020 // a better short ver. is 1/2 2020 but its not supported abmonth: "jan,feb,mar,apr,maj,jun,jul,aug,sep,okt,nov,dec", @@ -322,7 +322,7 @@ var locales = { speed: "km/h", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d. %b. %Y", 1: "%d/%m %Y" }, // 1. feb. 2020 // 01/02 2020 // a better short ver. is 1/2 2020 but its not supported abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", @@ -370,7 +370,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%y" }, // Sonntag, 1. März 2020 // 01.03.20 abmonth: "Jän,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez", @@ -403,7 +403,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%A, %d de %B de %Y", "1": "%d/%m/%y" }, // domingo, 1 de marzo de 2020 // 01/03/20 abmonth: "ene,feb,mar,abr,may,jun,jul,ago,sept,oct,nov,dic", @@ -420,7 +420,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%y" }, // dimanche 1 mars 2020 // 01/03/20 abmonth: "janv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.", @@ -484,7 +484,7 @@ var locales = { speed: 'kmh', distance: { "0": "m", "1": "km" }, temperature: '°C', - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM.%SS", 1: "%HH:%MM" }, // 17:00.00 // 17:00 datePattern: { 0: "%d %b %Y", "1": "%d/%m/%Y" }, // 1 marzo 2020 // 01/03/2020 abmonth: "gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic", @@ -500,7 +500,7 @@ var locales = { speed: 'kmh', distance: { "0": "m", "1": "km" }, temperature: '°C', - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM.%SS", 1: "%HH:%MM" }, // 17:00.00 // 17:00 datePattern: { 0: "%d %b %Y", "1": "%d/%m/%Y" }, // 1 marzo 2020 // 01/03/2020 abmonth: "gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic", @@ -516,7 +516,7 @@ var locales = { speed: 'kmh', distance: { "0": "m", "1": "km" }, temperature: '°C', - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH.%MM.%SS", 1: "%HH.%MM" }, // 17.00.00 // 17.00 datePattern: { 0: "%A, %d. %B %Y", "1": "%Y-%m-%d" }, // Sunntag, 1. Märze 2020 // 2020-03-01 abmonth: "Jen,Hor,Mär,Abr,Mei,Brá,Hei,Öig,Her,Wím,Win,Chr", @@ -564,7 +564,7 @@ var locales = { speed: "km/h", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%A %d %B de %Y", "1": "%d/%m/%Y" }, // dimenge 1 de març de 2020 // 01/03/2020 abmonth: "gen.,febr.,març,abril,mai,junh,julh,ago.,set.,oct.,nov.,dec.", @@ -660,7 +660,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d. %b %Y", "1": "%d.%m.%Y" }, // 1. Mar 2021 // 01.03.2021 abmonth: "Sty,Lut,Mar,Kwi,Maj,Cze,Lip,Sie,Wrz,Paź,Lis,Gru", @@ -676,7 +676,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d. %b %Y", "1": "%d.%m.%Y" }, // 1. Mar 2020 // 01.03.20 abmonth: "Jan,Feb,Mar,Apr,Mai,Jūn,Jūl,Aug,Sep,Okt,Nov,Dec", @@ -692,7 +692,7 @@ var locales = { speed: "kmt", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d. %b %Y", "1": "%d.%m.%Y" }, // 1. Mar 2020 // 01.03.20 abmonth: "Jan,Feb,Mar,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Des", @@ -708,7 +708,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d. %b %Y", "1": "%d.%m.%Y" }, // 1. Mar 2020 // 01.03.20 abmonth: "Jan,Feb,Mar,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Des", @@ -725,7 +725,7 @@ var locales = { speed: "kmh", distance: { 0: "m", 1: "km" }, temperature: "°C", - ampm: { 0: "", 1: "" }, + ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, datePattern: { 0: "%d %B %Y", "1": "%d/%m/%y" }, abmonth: "gen.,febr.,març,abr.,maig,juny,jul.,ag.,set.,oct.,nov.,des.", diff --git a/apps/locale/sanitycheck.js b/apps/locale/sanitycheck.js index 06c7ad3d6..ceca89b8d 100644 --- a/apps/locale/sanitycheck.js +++ b/apps/locale/sanitycheck.js @@ -4,15 +4,15 @@ */ const datetime_length_map = { // %A, %a, %B, %b vary depending on the locale, so they are calculated later - "%Y": [4, 4], - "%y": [2, 2], - "%m": [2, 2], - "%-m": [1, 2], - "%d": [2, 2], - "%-d": [1, 2], - "%HH": [2, 2], - "%MM": [2, 2], - "%SS": [2, 2], + "%Y": [4, 4, "2024", "2024"], + "%y": [2, 2, "24", "24"], + "%m": [2, 2, "10", "10"], + "%-m": [1, 2, "1", "10"], + "%d": [2, 2, "10", "10"], + "%-d": [1, 2, "1", "10"], + "%HH": [2, 2, "10", "10"], + "%MM": [2, 2, "10", "10"], + "%SS": [2, 2, "10", "10"], }; /** @@ -30,20 +30,21 @@ function getLengthOfDatetimeFormat(name, datetimeEspruino, locale, errors) { ["%a", locale.abday], ["%B", locale.month], ["%b", locale.abmonth], - ]){ + ]) { const length = [Infinity, 0]; for(const value of values.split(",")){ - if(length[0] > value.length) length[0] = value.length; - if(length[1] < value.length) length[1] = value.length; + if(length[0] > value.length) { length[0] = value.length; length[2] = value; } + if(length[1] < value.length) { length[1] = value.length; length[3] = value; } } length_map[symbol] = length; } // Find the length of the output - let formatLength = [0, 0]; + let formatLength = [0, 0, "", ""]; let i = 0; while (i < datetimeEspruino.length) { - if (datetimeEspruino[i] === "%") { + let ch = datetimeEspruino[i]; + if (ch === "%") { let match; for(const symbolLength of [2, 3]){ const length = length_map[datetimeEspruino.substring(i, i+symbolLength)]; @@ -57,16 +58,22 @@ function getLengthOfDatetimeFormat(name, datetimeEspruino, locale, errors) { if(match){ formatLength[0] += match.length[0]; formatLength[1] += match.length[1]; + formatLength[2] += match.length[2]; + formatLength[3] += match.length[3]; i += match.symbolLength; }else{ errors.push({name, value: datetimeEspruino, lang: locale.lang, error: `uses an unsupported format symbol: ${datetimeEspruino.substring(i, i+3)}`}); formatLength[0]++; formatLength[1]++; + formatLength[2]+=" "; + formatLength[3]+=" "; i++; } } else { formatLength[0]++; formatLength[1]++; + formatLength[2]+=ch; + formatLength[3]+=ch; i++; } } @@ -154,10 +161,10 @@ function checkLocale(locale, {speedUnits, distanceUnits, codePages, CODEPAGE_CON function checkFormatLength(name, value, min, max) { const length = getLengthOfDatetimeFormat(name, value, locale, errors); if (min && length[0] < min) { - errors.push({name, value, lang: locale.lang, error: `output must be longer than ${min-1} characters`}); + errors.push({name, value, lang: locale.lang, error: `output must be longer than ${min-1} characters (${length[2]} -> ${length[0]})`}); } if (max && length[1] > max) { - errors.push({name, value, lang: locale.lang, error: `output must be shorter than ${max+1} characters`}); + errors.push({name, value, lang: locale.lang, error: `output must be shorter than ${max+1} characters (${length[3]} -> ${length[1]})`}); } } function checkIsIn(name, value, listName, list) { diff --git a/apps/powermanager/interface.html b/apps/powermanager/interface.html index 51c31cc81..450ad4f26 100644 --- a/apps/powermanager/interface.html +++ b/apps/powermanager/interface.html @@ -148,7 +148,7 @@ function viewDeferredTable(filename) { //try finding possible sources for the given function, currently does not work because function.toString() not being identical to code in the *.js files. - /*Puck.eval(`require("Storage").list(/.*.js$/)`, (f)=>{ + /*Puck.eval(`require("Storage").list(/.*\.js$/)`, (f)=>{ console.log("Found files:", f, rows[1].func); for (let file of f){ let query = `require("Storage").read('${file}').includes('${rows[1].func}')`; diff --git a/apps/sched/ChangeLog b/apps/sched/ChangeLog index 39e26a116..eab8dd305 100644 --- a/apps/sched/ChangeLog +++ b/apps/sched/ChangeLog @@ -29,4 +29,5 @@ 0.26: Fix hitting snooze on an alarm after when the snooze would've fired 0.27: Tapping clkinfo enables/disables the selected alarm 0.28: Added an icon for disabled events -0.29: Fix possible bug in toggling an alarm to on, from clkinfo +0.29: Improve clkinfo startup time by 10ms +0.30: Fix possible bug in toggling an alarm to on, from clkinfo diff --git a/apps/sched/clkinfo.js b/apps/sched/clkinfo.js index 92dd6c4fd..266eb7bde 100644 --- a/apps/sched/clkinfo.js +++ b/apps/sched/clkinfo.js @@ -1,15 +1,7 @@ (function() { - const alarm = require('sched'); - const iconAlarmOn = atob("GBiBAAAAAAAAAAYAYA4AcBx+ODn/nAP/wAf/4A/n8A/n8B/n+B/n+B/n+B/n+B/h+B/4+A/+8A//8Af/4AP/wAH/gAB+AAAAAAAAAA=="); - const iconAlarmOff = atob("GBiBAAAAAAAAAAYAYA4AcBx+ODn/nAP/wAf/4A/n8A/n8B/n+B/n+B/nAB/mAB/geB/5/g/5tg/zAwfzhwPzhwHzAwB5tgAB/gAAeA=="); - const iconTimerOn = atob("GBiBAAAAAAAAAAAAAAf/4Af/4AGBgAGBgAGBgAD/AAD/AAB+AAA8AAA8AAB+AADnAADDAAGBgAGBgAGBgAf/4Af/4AAAAAAAAAAAAA=="); - const iconTimerOff = atob("GBiBAAAAAAAAAAAAAAf/4Af/4AGBgAGBgAGBgAD/AAD/AAB+AAA8AAA8AAB+AADkeADB/gGBtgGDAwGDhwfzhwfzAwABtgAB/gAAeA=="); - const iconEventOn = atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B/++B/8+B/5+B8z+B+H+B/P+B//+B//+B//+A//8AAAAAAAAAAAAA=="); - const iconEventOff = atob("GBgBAAAAAAAAAAAAD//wH//4GAAYGAAYGAAYH//4H//4H//4H/74H/wAH/gAHzB4H4H+H8m2H/MDH/OHH/OHD/MDAAG2AAH+AAB4"); - //from 0 to max, the higher the closer to fire (as in a progress bar) - function getAlarmValue(a){ - let min = Math.round(alarm.getTimeToAlarm(a)/(60*1000)); + function getAlarmValue(a) { + let min = Math.round(require('sched').getTimeToAlarm(a)/(60*1000)); if(!min) return 0; //not active or more than a day return getAlarmMax(a)-min; } @@ -23,20 +15,20 @@ function getAlarmIcon(a) { if(a.on) { - if(a.timer) return iconTimerOn; - if(a.date) return iconEventOn; - return iconAlarmOn; + if(a.timer) return atob("GBiBAAAAAAAAAAAAAAf/4Af/4AGBgAGBgAGBgAD/AAD/AAB+AAA8AAA8AAB+AADnAADDAAGBgAGBgAGBgAf/4Af/4AAAAAAAAAAAAA=="); + if(a.date) return atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B/++B/8+B/5+B8z+B+H+B/P+B//+B//+B//+A//8AAAAAAAAAAAAA=="); + return atob("GBiBAAAAAAAAAAYAYA4AcBx+ODn/nAP/wAf/4A/n8A/n8B/n+B/n+B/n+B/n+B/h+B/4+A/+8A//8Af/4AP/wAH/gAB+AAAAAAAAAA=="); } else { - if(a.timer) return iconTimerOff; - if(a.date) return iconEventOff; - return iconAlarmOff; + if(a.timer) return atob("GBiBAAAAAAAAAAAAAAf/4Af/4AGBgAGBgAGBgAD/AAD/AAB+AAA8AAA8AAB+AADkeADB/gGBtgGDAwGDhwfzhwfzAwABtgAB/gAAeA=="); + if(a.date) return atob("GBgBAAAAAAAAAAAAD//wH//4GAAYGAAYGAAYH//4H//4H//4H/74H/wAH/gAHzB4H4H+H8m2H/MDH/OHH/OHD/MDAAG2AAH+AAB4"); + return atob("GBiBAAAAAAAAAAYAYA4AcBx+ODn/nAP/wAf/4A/n8A/n8B/n+B/n+B/nAB/mAB/geB/5/g/5tg/zAwfzhwPzhwHzAwB5tgAB/gAAeA=="); } } function getAlarmText(a){ if(a.timer) { if(!a.on) return /*LANG*/"off"; - let time = Math.round(alarm.getTimeToAlarm(a)/(60*1000)); + let time = Math.round(require('sched').getTimeToAlarm(a)/(60*1000)); if(time > 60) time = Math.round(time / 60) + "h"; else @@ -52,7 +44,7 @@ //workaround for sorting undefined values function getAlarmOrder(a) { - let val = alarm.getTimeToAlarm(a); + let val = require('sched').getTimeToAlarm(a); if(typeof val == "undefined") return 86400*1000; return val; } @@ -66,7 +58,7 @@ const minute = 60 * 1000; const halfhour = 30 * minute; const hour = 2 * halfhour; - let msecs = alarm.getTimeToAlarm(a); + let msecs = require('sched').getTimeToAlarm(a); if(typeof msecs == "undefined" || msecs == 0) return []; if(msecs > hour) { //refresh every half an hour @@ -103,15 +95,15 @@ }, switchTimeout); } - var img = iconAlarmOn; - var all = alarm.getAlarms(); + // read the file direct here to avoid loading sched library (saves 10ms!) + var all = /*require('sched').getAlarms()*/require("Storage").readJSON("sched.json",1)||[]; //get only alarms not created by other apps var alarmItems = { name: /*LANG*/"Alarms", - img: img, + img: getAlarmIcon({on:1}), dynamic: true, items: all.filter(a=>!a.appid) - //.sort((a,b)=>alarm.getTimeToAlarm(a)-alarm.getTimeToAlarm(b)) + //.sort((a,b)=>require('sched').getTimeToAlarm(a)-require('sched').getTimeToAlarm(b)) .sort((a,b)=>getAlarmOrder(a)-getAlarmOrder(b)) .map(a => ({ name: null, @@ -136,13 +128,12 @@ if (a.date) return; // ignore events a.on = !a.on; a.last = 0; - if(a.on && a.timer) alarm.resetTimer(a); + if(a.on && a.timer) require('sched').resetTimer(a); this.emit("redraw"); - alarm.setAlarms(all); - alarm.reload(); // schedule/unschedule the alarm + require('sched').setAlarms(all); + require('sched').reload(); // schedule/unschedule the alarm } })), }; - return alarmItems; }) diff --git a/apps/sched/lib.js b/apps/sched/lib.js index fcd971fc4..e11448a18 100644 --- a/apps/sched/lib.js +++ b/apps/sched/lib.js @@ -1,5 +1,6 @@ // Return an array of all alarms exports.getAlarms = function() { + // we do this direct in clkinfo.js to avoid loading the library return require("Storage").readJSON("sched.json",1)||[]; }; // Write a list of alarms back to storage diff --git a/apps/sched/metadata.json b/apps/sched/metadata.json index 274b83d14..7e3458ae6 100644 --- a/apps/sched/metadata.json +++ b/apps/sched/metadata.json @@ -1,7 +1,7 @@ { "id": "sched", "name": "Scheduler", - "version": "0.29", + "version": "0.30", "description": "Scheduling library for alarms and timers", "icon": "app.png", "type": "scheduler", diff --git a/apps/sudoku/ChangeLog b/apps/sudoku/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/sudoku/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/sudoku/app-icon.js b/apps/sudoku/app-icon.js new file mode 100644 index 000000000..6762e0c1a --- /dev/null +++ b/apps/sudoku/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("l0vwQPM/4AI+E4ChEDwYgJhkwgGAgYHChED3cACwM8gHwBYXwn/wCwMLwELBQULgeACxXACwIPBCwotKAIIWIAAIWCn5EJgewFou4CwQpDAYhyCCQJWBgE7BwWDh6gICwgtDCwYtOF4QWIgf8CxMwL4gtFh7OGCwS0CCxABB4AWHnBbJIhc7LZI2DCw4AFwcDTIPw/6lD/gWB3YABhewAgW72CgQW6wWphELhYCBgYEBgYWC+AAHCwIQBAAwtEHgTOHAA+DB4QAGnk7TYYAFwCxCAAzVGAAo")) diff --git a/apps/sudoku/app.js b/apps/sudoku/app.js new file mode 100644 index 000000000..5a7f9cd1f --- /dev/null +++ b/apps/sudoku/app.js @@ -0,0 +1,163 @@ +var settings = require("Storage").readJSON("sudoku.json",1)||{}; + +const Layout = require("Layout"); +var puzzle = ""; // start puzzle space for blanks, 81 char str +var solution = ""; // the solution for the puzzle 81 char str +var current = ""; // current puzzle state, 81 char str +var sx=4, sy=4; // selected item +var dx=0, dy=0, dmoved=false; // current drag amount +const DRAG = 20; +const CHOOSERFONT = "12x20:2"; +const COL_GOOD = "#00F"; +const COL_BAD = "#F00"; + +function saveSettings() { + settings.puzzle = puzzle; + settings.solution = solution; + settings.current = current; + require("Storage").writeJSON("sudoku.json",settings); +} + +function startGame(difficulty) { + let file = require("Storage").read("sudoku.easy.txt"); + let games = 0|(file.length/163); + let game = Math.floor(Math.random()*games); + let line = file.substr(game*163, 162); + puzzle = line.substr(0,81).replaceAll("-"," "); + current = ""+puzzle; // new string + solution = line.substr(81,81); + showGrid(); +} + +function draw() { + g.clear(1); + for (var i=0;i<10;i++) { + g.setColor((i%3)?"#888":g.theme.fg); + g.fillRect(7+18*i, 7, 7+18*i, 169); + g.fillRect(7, 7+18*i, 169, 7+18*i); + } + i = 0; + g.setFont("6x8:2").setFontAlign(0,0); + for (var y=0;y<9;y++) + for (var x=0;x<9;x++) + g.setColor(puzzle[i]==" "?((solution[i]==current[i])?COL_GOOD:COL_BAD):g.theme.fg).drawString(current[i++], 16 + 18*x, 16 + 18*y); +} +function drawSq(x,y,sel) { + g.setColor(sel ? g.theme.bgH : g.theme.bg).fillRect(8+x*18,8+y*18,24+x*18,24+y*18); + g.setFont("6x8:2").setFontAlign(0,0).setColor(sel ? g.theme.fgH : g.theme.fg); + var i = x+y*9; + g.setColor(puzzle[i]==" "?((solution[i]==current[i])?COL_GOOD:COL_BAD):g.theme.fg).drawString(current[i++], 16 + 18*x, 16 + 18*y); +} + +// precalculate our layout +var choose = function(num) { + if (num!==undefined) { + Bangle.buzz(100); + var i = sx+sy*9; + current = current.substr(0,i)+num+current.substr(i+1); + } + showGrid(); + if (current == solution) { + saveSettings(); + E.showMessage(/*LANG*/"Well done,\nyou finished!", { + title:"Sudoku", + buttons : {"Ok":true}, + img : require("heatshrink").decompress(atob("k8pwcBkmSpICCnVp0IIFAQl27dt2wOJ9On7/582YtOJBws7tv/DoQKCBwubvvmzVp0wCCHAvf9u2DpE8uOn7waEjQdDq1Itv+DQQCB0gZBkMkyPHj1tHAuGAQOJktt/Ubvo4DAQI3ChMcuPHzd5HAeasICBtFOr/kw3fDQe27RhCofH/lx4xxFSQIFBiu/rNhHAp0DyHx447BHAh0Ekt/61YlodFOgaPBDoJWFAQeJrf1yySBDohWCoVJOgUcKw+YyVOrtly0LKw4eBp4dCjytHBwNOrNlyUbDoVpHAYDBo4dH02EFoTpBDoQ7B2MyZALMCHYsGtOOjALDAQQ7CyM6tFkFIgCDDoPBnkT4wLFAQegxP8z/JBxNwp8E+ALHAQMl+V/n4aIAQI4B4McBxU/z/P8gOKjnx4JHJAQP//5WKSoVwDRICBv//FJTRDBxeT/5WLkmR45WLkitLARNIA")) + }).then(showMenu); + } +}; +var numberChooser = new Layout( { + type:"v", c: [ + {type:"h", c: [ + {type:"btn", font:CHOOSERFONT, label:"1", fillx:1, cb:()=>choose(1) }, + {type:"btn", font:CHOOSERFONT, label:"2", fillx:1, cb:()=>choose(2) }, + {type:"btn", font:CHOOSERFONT, label:"3", fillx:1, cb:()=>choose(3) } + ]}, + {type:"h", c: [ + {type:"btn", font:CHOOSERFONT, label:"4", fillx:1, cb:()=>choose(4) }, + {type:"btn", font:CHOOSERFONT, label:"5", fillx:1, cb:()=>choose(5) }, + {type:"btn", font:CHOOSERFONT, label:"6", fillx:1, cb:()=>choose(6) } + ]}, + {type:"h", c: [ + {type:"btn", font:CHOOSERFONT, label:"7", fillx:1, cb:()=>choose(7) }, + {type:"btn", font:CHOOSERFONT, label:"8", fillx:1, cb:()=>choose(8) }, + {type:"btn", font:CHOOSERFONT, label:"9", fillx:1, cb:()=>choose(9) } + ]} + ], fillx:1 +}, {btns:[ {label:/*LANG*/"Back", cb: l=>choose()} ]}); + +function showGrid() { + Bangle.setUI({mode:"custom", drag:e=>{ + if (e.b) { + dx += e.dx; + dy += e.dy; + while (Math.abs(dx) >= DRAG) { + Bangle.buzz(40); + let old = sx; + sx = (sx+9+Math.sign(dx))%9; + dx -= Math.sign(dx)*DRAG; + drawSq(old,sy,0); + drawSq(sx,sy,1); + dmoved = true; + } + while (Math.abs(dy) >= DRAG) { + Bangle.buzz(40); + let old = sy; + sy = (sy+9+Math.sign(dy))%9; + dy -= Math.sign(dy)*DRAG; + drawSq(sx,old,0); + drawSq(sx,sy,1); + dmoved = true; + } + } else { + if (!dmoved && puzzle[sx+sy*9]==" ") { + Bangle.buzz(100); + setTimeout(showSelectNumber, 10); + } + dx = dy = 0; + dmoved = false; + } + }, btn:() => { + saveSettings(); + showMenu(); + }}); + draw(); + drawSq(sx,sy,1); +} + +function showSelectNumber() { + g.clear(); + numberChooser.setUI(); + numberChooser.render(); +} + +function showMenu() { + var menu = { "" : { title: "Sudoku" } }; + if (settings.puzzle) + menu["Resume Game"] = () => { + puzzle = settings.puzzle; + solution = settings.solution; + current = settings.current; + showGrid(); + }; + menu["New Game"] = () => { + E.showMenu({ "" : { title: /*LANG*/"Difficulty", back : showMenu }, + "Easy" : () => startGame("easy"), + "Medium" : () => startGame("medium"), + "Hard" : () => startGame("hard") + }); + }; + menu["Exit"] = () => load(); + E.showMenu(menu); +} + +if (settings.puzzle) { + puzzle = settings.puzzle; + solution = settings.solution; + current = settings.current; + showGrid(); +} else { + showMenu(); +} + +E.on("kill", saveSettings); // ensure we save the game diff --git a/apps/sudoku/app.png b/apps/sudoku/app.png new file mode 100644 index 000000000..ab5f449e8 Binary files /dev/null and b/apps/sudoku/app.png differ diff --git a/apps/sudoku/gen_sudoku.js b/apps/sudoku/gen_sudoku.js new file mode 100644 index 000000000..002c0a7d1 --- /dev/null +++ b/apps/sudoku/gen_sudoku.js @@ -0,0 +1,24 @@ +/* +Call this to generate the data files needed. + +npm install sudoku-gen + +*/ + +var getSudoku = require('sudoku-gen').getSudoku; + +// (easy, medium, hard, expert) +function gen(difficulty) { + console.log("Generate", difficulty); + // Get a sudoku of specific difficulty + let result = ""; + for (let i=0;i<200;i++) { + const sudoku = getSudoku('easy'); + result += sudoku.puzzle + sudoku.solution+"\n"; + } + require("fs").writeFileSync("sudoku."+difficulty+".txt", result); +} + +gen("easy"); +gen("medium"); +gen("hard"); diff --git a/apps/sudoku/metadata.json b/apps/sudoku/metadata.json new file mode 100644 index 000000000..63a534acf --- /dev/null +++ b/apps/sudoku/metadata.json @@ -0,0 +1,17 @@ +{ "id": "sudoku", + "name": "Sudoku", + "shortName":"Sudoku", + "version":"0.01", + "description": "A Sudoku game that allows you to play one of 600 pre-made puzzles", + "icon": "app.png", + "screenshots" : [ { "url":"screenshot.png" } ], + "tags": "game", + "supports" : ["BANGLEJS2"], + "storage": [ + {"name":"sudoku.app.js","url":"app.js"}, + {"name":"sudoku.img","url":"app-icon.js","evaluate":true}, + {"name":"sudoku.easy.txt","url":"sudoku.easy.txt"}, + {"name":"sudoku.medium.txt","url":"sudoku.medium.txt"}, + {"name":"sudoku.hard.txt","url":"sudoku.hard.txt"} + ] +} diff --git a/apps/sudoku/screenshot.png b/apps/sudoku/screenshot.png new file mode 100644 index 000000000..490a49cc1 Binary files /dev/null and b/apps/sudoku/screenshot.png differ diff --git a/apps/sudoku/sudoku.easy.txt b/apps/sudoku/sudoku.easy.txt new file mode 100644 index 000000000..5937edea3 --- /dev/null +++ b/apps/sudoku/sudoku.easy.txt @@ -0,0 +1,200 @@ +8----47---47----639-5--381-7--46-13219---5---4----2597--13-724--2--46--83-4-----1813694725247581963965273814758469132192735486436812597681357249529146378374928651 +6------1-----954-3--94-1----76-3-----18562-94-927-4638--4-5----9--2--1-62-3----47645378219821695473739421865476839521318562794592714638164957382987243156253186947 +9-6-----3-186239-----945---3-521--8-4--3---1---189---46--57-1---7--38-9----16-47-946781523518623947237945861365214789489357216721896354694572138172438695853169472 +---4-71---895-27637128-3-495-7-8--3--94-31--------96---5--7---------8-959-1---8-6635497128489512763712863549567284931894631257123759684358976412276148395941325876 +4-5----97-92-4-------6--2--7---68----89-14763651-324-9---17-9-8-1-4---265---9----465321897192847635873659214734968152289514763651732489326175948917483526548296371 +1---23986------154--819-----3-4--8---2-85-6-3--4-3-2-147----3-93--9--5-7-1---7-28147523986293678154568194732639412875721859643854736291476285319382941567915367428 +--6-25837-2--891-6-3-74-5-947-21---5---97--8------4---59-8-23-----4--9-2---5974-8946125837725389146138746529473218695651973284289654713594862371867431952312597468 +--5---61-4---1-------6-9-25-5349786--84-----9-17-562345--1-43----6-----23-9-68---895742613462315978731689425253497861684231759917856234578124396146973582329568147 +3--16-9--------32794-7-5---6-9-2---18-1---459--489-6-27-628319--------68---6-92-3387162945165948327942735816639524781821376459574891632756283194293417568418659273 +------1---2---3----8---6-4564--3-28-2938-4--68--6-7493---9--5--358---9729-4--2618436785129529143867781296345647539281293814756815627493162978534358461972974352618 +-96--1-521354-6-9---------6974182-632--597--1---6--7--5192---7-3--7-----6-7--4-35496871352135426897728359146974182563263597481851643729519238674342765918687914235 +-9127----------562-5-4-89--43----1791--3-98-698---6--4---89-6-582-65349--------83691275348748931562253468917436582179172349856985716234314897625827653491569124783 +58----24-----1--8-3-72--9--6435-8-2989-132-67----4--35-7----3-----8-7-9-4-8-91---589763241264915783317284956643578129895132467721649835972456318136827594458391672 +2--4-3-756--5----1----6129-3--74----8--6--143-961--82796--8-5-----2-67--1-2--7-68218493675649572381753861294321748956875629143496135827967384512584216739132957468 +---5--3-86---34-5235--27--6-49----3--6-31--4----47-28-8-67-391413----7--9----286-492561378687934152351827496749285631268319547513476289826753914134698725975142863 +76---9--5142--83--98--31-7--29-7-5-157---2-6-8-1---7--4--187--3----461-92-8-----7763429815142758396985631472629874531574312968831965724496187253357246189218593647 +--476-53-9-6-3-4-1-----9------18------295-7-359-473--21-9-2-3-47---9-1-646351---7284761539976835421315249678637182945842956713591473862159627384728394156463518297 +-3--9-----29-46--81-82-75-6--4---3---15--2---9---5-461-9--75684--1--49-7-57--921-536891742729546138148237596674918325315462879982753461293175684861324957457689213 +-863--2-9--17--6--34-----718-----3-76--47--5--751-3--81295--7-----9--82-538-471--786315249951724683342869571894652317613478952275193468129586734467931825538247196 +--13-98--7---21--4----471-692--543---4--38-6-6---9-4-----286---87-----9--34975--8451369827768521934392847156927654381145738269683192475519286743876413592234975618 +1--93-46-3-4--1----9---7-83--61493-8-21----5---3526-9-63--84-----76---3-5-271--4-178932465364851279295467183756149328921378654843526791639284517417695832582713946 +-1-7-8--5--4-65-2--59-42---9---714---7--3468--4--8--9----619---8-----21---18237-4612798345784365921359142876968271453175934682243586197427619538836457219591823764 +9132-5--4874----------439---21-98-5--45--27----9-7--2--68-3---259-6---4--32----67913285674874916235256743918721398456345162789689574321168437592597621843432859167 +-8---63--3---42--8-2--816-7--8-975---4-26--9--93-58------734-----4615-826-----4-5581976324376542918429381657268197543745263891193458276852734169934615782617829435 +81-64-379----89------7-348-69-524---48---6--75--8-7-94-45---21----371----3-4---68812645379374289156956713482697524831483196527521837694745968213268371945139452768 +9--8--4-5----641-94-6-95---713-42----4--8-25-2------3-1-2--85473974----65--726---921873465835264179476195382713542698649387251258619734162938547397451826584726913 +2-4--5---75-48---99--73--54-273-8----8-6-4-9--4----18--92-7---1--3----46861-439-2234965718756481329918732654127398465385614297649257183492876531573129846861543972 +2---------95-86--3--87-32-5-268-9--1-74------8391--62--679--358--25-79----13-87-2213495876795286143648713295526879431174632589839154627467921358382567914951348762 +--6-----2-2-6-791-57--286-4-9-7563-8--78--56---------9--34-2---1-5369--7--258-4-3316945872824637915579128634491756328237894561658213749983472156145369287762581493 +-3--27--52----6---496----233-1----788--73-5-----89--316841--3--9-2473-5-7-----412138927645275346189496518723341265978829731564567894231684152397912473856753689412 +-617--52-5-74--6--48325--7---9---4-----1--26-634-2---7----7--9-8--34-71-3-25-18-6961783524527419638483256971219867453758134269634925187145678392896342715372591846 +98-----71-1---3---5---9-42--27--8----64932-15-9517-2682-------4-5-41-------3-518-983246571412753896576891423127568349864932715395174268231687954758419632649325187 +-39-2--16-8--19---164-83---41-3-----79---6-48--8------3-1-75-9-9-62345--84--61-2-539427816287619453164583972412398765793156248658742139321875694976234581845961327 +1-8--6---526-73--4-93--18-62345--6-9--9--432---------591-43-2-84-21--57------2--1148956732526873194793241856234587619859614327671329485917435268462198573385762941 +----96--8923------6854-79--7-9--4--38---3--4-5-4-82-7-4-6---31-2-1-6-4---781---9-147396258923851764685427931769514823812739546534682179496278315251963487378145692 +---264-----1---52-2--5713-8-2--13--969-85----8--49--5---632-8---3-78-41--8-1---6-358264971471938526269571348524613789697852134813497652146325897932786415785149263 +------437--524----4--1-9258-9--7-5---1-35-8-9--79--1-476----9-29---2-3-6-4---6-15129685437385247691476139258892471563614352879537968124768513942951724386243896715 +-3-8--47-91537------7---9----6--8-34---23--162-364----569--3--27-1-8-345--4725---632859471915374628847162953176598234498237516253641897569413782721986345384725169 +-24--13-5--7--84--16-----87-891-7--24---86-9-2-----1-891286-7-------523-735--98--824971365597638421163542987389157642471286593256394178912863754648715239735429816 +248-1--65--152---9-9548---3-------579-6-3-481-3-14--96-8-6-4-12------9---2985---4248319765371526849695487123412968357956732481837145296783694512564271938129853674 +57-6321----3--5-8-4-6---3-2---3----1---9---3-13--84-9676-24---8--186-27-2-915---3578632149923415687416798352894376521657921834132584796765243918341869275289157463 +4-258-7----3---------2635----9---4-26-7--81-55--1-28---7-621-84-1--9-25-24--356-1462589713853417926791263548189356472627948135534172869975621384316894257248735691 +679-8-3-5-14-----92-549---1----7------25-6--856892--7-12-64-58--867-3-1-----1---6679182345814365729235497861391874652742536198568921473123649587986753214457218936 +-2--6-------9-34-5--4----96--9---5---4-6-2-1--13-97---4-1238-797-2---3--6-8-49251925164738186973425374825196269381547847652913513497862451238679792516384638749251 +4-5----6-2-1-397488-94265-33------7--9-14-8--68--53----4---1---9-----3-1---36--97435718269261539748879426513314682975592147836687953124743891652956274381128365497 +7-4---85-----6874---8-45--1--32------4-53-1--269---43-982--7--43-6459-1---5---379794123856521968743638745921153294687847536192269871435982317564376459218415682379 +--8---9729-6428-5-231-7---47-4---38-----3674---3-84--5162---49--4-8-95----91-----458613972976428153231975864724591386815236749693784215162357498347869521589142637 +--46-19-5-5-------2-9-481--5-84-23--6-7------1423---58--31-45-6--59-6--28-62--491784631925351729864269548173598462317637815249142397658923174586415986732876253491 +82-43---9-4--6----7-39-1-58---2---6-3--51-----5---482157--4-9824--75-13-2--1---47825437619149865273763921458914278365382516794657394821571643982498752136236189547 +------75937-2-----8-4--7321-9--4-2--52--8-1-44--9--8-7--6-7--82-3---45-6----694-3612438759379215648854697321798341265523786194461952837146573982937824516285169473 +3--25---7------6137-4-19---27-6---5-85----974-4-78--62----27-36------28-12-8637-5318256497592478613764319528273694851856132974941785362485927136637541289129863745 +6---8-3-519----2--3-529-64197--28-5-5---49-87---7--93----4-28-3-5-9-1--4-46-----9627184395194536278385297641971328456532649187468715932719452863853961724246873519 +5-------8-1-49--3-23--65----9---4------52-8-11-----45-3-197256-9-6-----27-4-51389549237618617498235238165947895314726473526891162789453381972564956843172724651389 +--9--2-84-6-5------72---6-192--6174383-4259-614-7-------4---8---9--86------95--67319672584468519372572348691925861743837425916146793258654137829791286435283954167 +-1------279---8-----69--74186-1-45--2--6------57-834-993---6-78-7---13-66--3-9154314765982792418635586932741863194527249657813157283469931546278475821396628379154 +9--8317------946-82-3---1--51---2-4--26-1-8-53-8-----114---65--892--3--763--78-1-964831752751294638283567194519782346426319875378645921147926583892153467635478219 +--8----7----3-------6-15-4-4-186-7--879--4-166--197-2491-436-8-765928------5----9598642173147389652236715948421863795879254316653197824912436587765928431384571269 +674----92-9-3-2-1---26-------8-391------87-595-9----83486-5-9--2-7943--1--3---425674815392895372614132694578728539146361487259549126783486251937257943861913768425 +---8-37--687--41---45---2-6---6-8--7--3-79-5--7-23-6-9-16-82-7---8346--1--2-579--921863745687524193345791286259618437163479852874235619516982374798346521432157968 +--4-9-57---1458-62-5273-8-418-6--4-7-7-5-46--9-----2-53--------52--671-----3857--834296571791458362652731894185629437273514689946873215367142958528967143419385726 +6-8---93--------469436-57-8---7-418248-1--69--9-8-6-7-76---38--5-2-18---------359628471935175389246943625718356794182487152693291836574769543821532918467814267359 +-6--7-5-89----523-51----7-66---1---23--82-6-4--16--9-3-9-3-6427--279----------189263179548978465231514238796647913852359827614821654973195386427482791365736542189 +4-158-9-------6----294--5-6-3-894-61---72-----4816-3---943--6-2-526----8-8-21-459461582973875936124329471586537894261916723845248165397794358612152649738683217459 +61-5-9------6--2---83--7-9-76-43-829---81-5--54897--163----8------7---63-56---7-2617529438495683271283147695761435829932816547548972316379268154824751963156394782 +2--3-4-15-1--8-32----2--6-478-4-5---624--97-------21-6-6-9--47194--2-56--5---328-276394815419586327835217694781465932624139758593872146362958471948721563157643289 +-68--9153--5-------438---2-3--15---9---9-86349-4-37815-5-78---2-----6-8-8125--7--268479153795312468143865927386154279571928634924637815659781342437296581812543796 +39-----57-26--741---4--39---1--7983-8--3-5--4-37-----1--953-1786-1--2-----3--8269398421657526987413174653982415279836862315794937864521249536178681792345753148269 +--28-3145-517--8-9-849--2----725139----6-8----253-9--7-185--9-4----9----53-4-2--1972863145651724839384915276467251398193678452825349617718536924246197583539482761 +2-3--1----89-2-613------4723---8-5-7-5-2--19----54-3-8--8--42-91-79--8-64--8----1243671985789425613615398472324189567856237194971546328568714239137952846492863751 +-4---1-2-31--28-9-2---694---7--53--2--591--6-----72-54---346---9-2187--676----1--649531728317428695258769431476853912825914367193672854581346279932187546764295183 +-7-4-9------37-9-61------4--15-6-----24813-79-879-5162-9--3----7----84-186-----95576489213248371956139256847915762384624813579387945162491537628752698431863124795 +39742-5-81-----6-3-648132-7-7-3-5-2----64--719-------4-45-----22-91-4-------5--3-397426518182579643564813297471395826853642971926781354745938162239164785618257439 +-3-689-2---54-2-631--5-7-4--5-26------71-5-8-61--48--546-----795--82----3--9--652734689521895412763126537948958263417247195386613748295462351879579826134381974652 +4-2-583-656--2--97---6--2--658-7-4-1-4-5---68------7--7168-95--23-1------842--1-3492758316561324897873691254658973421347512968129486735716839542235147689984265173 +2--68-5--17-23--8--5--7--2---97-8-6--4-91---2---42--958-2347--6---561---46----7--293684517174235689658179423329758164546913872781426395812347956937561248465892731 +9-68--4-5-----6---4--93-28-6-57--8-4--36--5-989452---3---15-----62348--77--26-3-8936812475258476931417935286625793814173684529894521763389157642562348197741269358 +-8----9-5456-237-13-95812-462-3-8-------7--5-7-3-----2--47-5-2--6------3----39-48281647935456923781379581264625398417198472356743156892834765129962814573517239648 +8-67-194337----1--9--2--8-6----142-8-6--37--4-49-----775-12--6-6--47--25-----578-826751943374896152915243876537614298268937514149582637753128469681479325492365781 +4-27-869--39-41-8--1--5---------35----4-76----6-1--379--3--712--26-1-938--1-624-7452738691639241785817659243178923564394576812265184379543897126726415938981362457 +-----95-29-2--5-368---461793-91--768-76--8--31---------415--8-75----7---2-786-35-764319582912785436835246179359124768476958213128673945641532897583497621297861354 +-2--79-5-7--1-------9--5762-4--563--3817-4---65793-4-8--------55364---172----7-83823679154765142839419385762942856371381724596657931428178263945536498217294517683 +2---75-968--9-4-13--16-8274---5-----75--83-6-----974------5--8996-84---2---769-45234175896876924513591638274489516327752483961613297458147352689965841732328769145 +6-75-8---8---9--4--34--2658---2--8------8-1---8261--791-58--2-42---359-6-639--5-7627548391851396742934172658719254863346789125582613479195867234278435916463921587 +--3--85-18-1--49-2259-613---862934--4---862-3----17------8-----9---35-265-8--21-9743928561861354972259761384186293457497586213325417698612849735974135826538672149 +---256----6-78491-7-----4-6--1--7--55---691----9-182-7--697--3--1--32--4-53-41---194256378365784912728193456481327695572469183639518247246975831917832564853641729 +31----97--7--8----4--3--6-5-4-7-5-------481-76------5--349-7216-2586374--69-1----318526974576489321492371685941735862253648197687192453834957216125863749769214538 +-4----372-1-9-346------2----547-1--6-6-4--5-3-93--8---6-9-1-73543--5--8--7539--24946185372512973468387642951254731896768429513193568247629814735431257689875396124 +6--18973-9-8---5-1-4--7---9-9-2------21-5469---69-----83-4-1--6--96-78-2--48-531-652189734978342561143576289495268173321754698786913425837421956519637842264895317 +---2-76-8------37-1-7638-257-2-8-5--3-5---249--9-238-76---75--229-4-1---------186953247618826159374147638925762984531385716249419523867631875492298461753574392186 +---6-814-1---53-296---9---8----162--46-7--9--8-1--2-67-46-8-7123--52----7---6-853293678145187453629654291378975816234462735981831942567546389712318527496729164853 +-534-8-7--94-26-1-1829-73--8---42-----9-75-26---6------1-78--49-68294----47-6----653418972794326815182957364876142593439875126521639487215783649368294751947561238 +15---84---3-4---8-89-3-6-5-78-----2426-7----83-5-2--1-416---------1-73--973-85--1157298463632451789894376152781563924269714538345829617416932875528147396973685241 +-916-25--3--49--1-5-----9-224----69---69----3-532--7-86871----9125-49--6---7---85891672534362495817574318962248537691716984253953261748687153429125849376439726185 +2-759-----3------4---3-7-9-4-3--6--917-----26----5--7-8247-196-----2-14-79-64538-217594638936812754548367291453276819179483526682159473824731965365928147791645382 +691-8-4----7-----1---2---6815983--4-3-41----6-624---835--91--24----4--7-9-83-26-5691783452827564931435291768159836247384127596762459183576918324213645879948372615 +35---29--62--7-154-1---------51-4-7-----27536-3758-412----6-2--492--1--81--2-8-9-354612987629873154718495623265134879841927536937586412583769241492351768176248395 +---8-6-4--8----3--1-654----96----21-----5--6-3-8--24--7136-9-2464-235-78----1--39537826941482791356196543782964378215271954863358162497713689524649235178825417639 +437---56859--8-123---5--7--3--16-95484539---11-9--483-------2----3-1--97--8-4----437921568596487123281536749372168954845392671169754832914673285623815497758249316 +--4267-5--7--5-24-2-------96523-18-4819----32-3-8--56-7---18-2-586-92--3-----5---394267158178953246265184379652371894819546732437829561743618925586792413921435687 +7418-356-----4-78--6397512--2------73-4-69------3-26------9-3--2-75----6-38---4-5741823569952146783863975124526481937384769251179352648415698372297534816638217495 +--26-13-884-5-91----97-8-54-2---3-----1--2----3597--212-8---5-7-9--6-2--1--285-46752641398846539172319728654927813465681452739435976821268394517594167283173285946 +8-23---19--1--7-637--1----8-5-6--38----57--414---1--52------276-13-6-8946-4--8---842356719591287463736194528159642387328579641467813952985431276213765894674928135 +------91687--21---9--5-38--4-3---782--78-456-5-86---3--------45----8569-1-54963-8352748916876921453941563827463159782217834569598672134689317245734285691125496378 +--9-18-5----3----8587-9-1---2--79-4----84-36264-1-28978-34--7292-6-8---59--------439718256162354978587296134328679541791845362645132897853461729276983415914527683 +--9-----4---465219-2--39678-18--6593-369528--5--3-8-62-5-2-------------7-8-6--43-169827354873465219425139678218746593736952841594318762357294186641583927982671435 +8-6---5-9-94------25--196489-8--3-54375-42-----2-95-8-5---6--92---35-7-1681------816234579794586123253719648968173254375842916142695387537461892429358761681927435 +---1-459---927--8-3-----4---74---8--83-54---------7-2-2934-86-75-----2-1-416259-8627184593459273186318956472974362815832541769165897324293418657586739241741625938 +-7-1-42--5--98--1-13-2-7-----9---5-2-5-692-78---345-----35-8--77----93--8--7-69-4978164253524983716136257849649871532351692478287345691493528167762419385815736924 +---375---81-649-5-9-5-----63-6-148----7--61--1---58--7--9-23-1-----9127--2-86-5--264375981813649752975182436396714825587236149142958367759423618638591274421867593 +94---16-33-1--6---625-897--4----7-29------5--7925--4-6-----21---1479-3-22-71---85948271653371456298625389741453617829186924537792538416539862174814795362267143985 +--6-957-1--2-8134--5-2746-8--------33-4--896----7--41-----37184----16-3-8-1-2--76486395721972681345153274698617942853324158967598763412269537184745816239831429576 +6-3---4--2--7-3--97-9--21-51--92-3-6------8--9--358---5-7-89-63-26537-1-39--4--7-613895427254713689789462135178924356435671892962358741547189263826537914391246578 +----78-598--961-4-2-1----6-51--946--67--5--3-982-1---4-25--6-9336--2-7--1-9-----6436278159857961342291345867513794628674852931982613574725186493368429715149537286 +3952----88-7--15-4--48-------25389-----7---8-1839624-773---92-5------7--5491-7--3395246178867391524214875639472538916956714382183962457731689245628453791549127863 +--915-8726-2--3-----1--896319----75---4--1--9-36--7-24-17---2--8---154---2-7-9-18349156872682973541751428963198342756274561389536897124917684235863215497425739618 +869-3175--45-792182---48------9-254--9-7---836----5----53--7---7-6----25---8--3--869231754345679218217548936138962547592714683674385192953427861786193425421856379 +---3-85--49----72-352--41--5--78-26--8--56--9---2-3-5--7--956---3-842-1-12--37--5716328594498561723352974186543789261281456379967213458874195632635842917129637845 +2-9---5-715--9---------3-1-42318--9556-94-378--763------2-5--------74-56-4---91-3239418567154796832876523419423187695561942378987635241692351784318274956745869123 +395---4-1-4----5-881-95-2---53----1--8743---94---------34-2-9-59-8--61235-1-8-7-6395278461742163598816954237253697814187432659469815372634721985978546123521389746 +631----5--4-57162---7--319837-2-8-----47-5-8-85----37-----9--6-4--65---776----912631829754948571623527463198376218549194735286852946371283197465419652837765384912 +---9-1-------68-945-942-1689-4--26--1-2734-----3-9641----685---43-----578---4-92-648971235321568794579423168984152673162734589753896412297685341436219857815347926 +37--98--5---1-----5-2--71-8--9-325872-8--19--7-5--42-1--475931-----26---9-7-13--4371298465896145723542367198419632587238571946765984231684759312153426879927813654 +-6-7-----8-1-6-7-972--93-6545--8-9373-79--5---8----------4--2-624-6--35--9-3-1478569714823831265749724893165456182937317946582982537614173458296248679351695321478 +--98-15--7-----6-82-45--1-98-6-592--3-----------3489---2-184-56-1--7-89--6893-4-1639821547751493628284567139846759213395216784172348965927184356413675892568932471 +6-3-98-7-7-1-6---2954-3-8--4--973--8----149-653------7-65--72-92-7-5--1-39----7--623198475781465392954732861416973528872514936539286147165347289247859613398621754 +-9146--7-7-6----4-3542---18---3-------9-15-2-51294-3--97-65-2-12-5-387-----7---5-891463572726581943354279618487326195639815427512947386978654231245138769163792854 +5----6---743-9--26619---538----8-9---25-7-3--4----------7-23689268-17--393-8--2-7582136794743598126619742538371284965825679341496351872157423689268917453934865217 +26-4-1-59-5--371-6--15------7-9-8621---7-------6-129----58-429---8---4-53-26--817267481359954237186831569742473958621129746538586312974615874293798123465342695817 +75829-1-4-6----5-39-36157-2--7-54-2--8----9-----93-67----4---5-82--69---4-9---2--758293164261748593943615782697854321382176945514932678136427859825369417479581236 +625-1-39-381---4577--3-----93468-5----659-14315---46-9-97-6---5----4---12--------625417398381926457749358216934681572876592143152734689497163825568249731213875964 +47-2-89---92-6--7-8-39-------1--5398---8-416-3-7--9----69--2-4-7185---3--34-9-58-476258913192463875853971624641725398925834167387619452569382741718546239234197586 +6-7-4-8---5-------18-5--467-2--7----5-92--7-473-4-6-28-4--69175----1-3-231--2-68-697142853453687291182593467824971536569238714731456928248369175976815342315724689 +-49--2-5--6-----138516-394---3---5-8--831---9-2486----2-7-38-9-43-7-----9---26-37349182756762954813851673942193247568678315429524869371217538694436791285985426137 +---7--9288--3596--9761-2--4---6-8-5751-----8676-5--4----32------27-6--4----913-62351746928842359671976182534234698157519437286768521493693274815127865349485913762 +-17432-8----856---8-4-----25--2--1----178---52-631-7-----14-95--9--278--4--69--1-617432589329856471854971362578269134931784625246315798762148953193527846485693217 +-9------38--5431--1-38---4-5-8--2-6--12-7638563----972-6-93-528----8----3--72---4496217853827543196153869247578392461912476385634158972761934528245681739389725614 +-9-523-611---4-------719438--839-6-236---218927-168--3----5-----8----9---2-6-43--894523761137846295652719438418395672365472189279168543743951826586237914921684357 +4---5----6-9---34---79--2-897-3-416223--6----18-52947---2----8-----756-47--4-8---428753916659812347317946258975384162234167895186529473542631789891275634763498521 +---8--3---6-23--7-37----49825----7-171--95-----6-725--134---2--6--7249-3--7--1854591847326468239175372516498259683741713495682846172539134958267685724913927361854 +17-269-38------6-1---1-892-81--2-3--36----8545--68-21--9-31--8-------792-857-4---174269538928537641653148927819425376362971854547683219796312485431856792285794163 +53--467-----1-----7-8-3-4-1--6-853478-4-1---63-7-2-1-8--2367-15----98---6-3-512--531846792469172583728539461216985347854713926397624158942367815175298634683451279 +--274-6-----29--343-4----27--7---8131-9874--68253--4--598----41-4--17-6---1--5---912743685756298134384156927467529813139874256825361479598632741243917568671485392 +---7-39-29376---45-5--8-7--7----6---1---7-----28-19-763-2--8-946-5--71-38-934-6--481753962937621845256984731794536218163872459528419376372168594645297183819345627 +7648--53--5--9---4---4-61-74----8---2---4-----19-2784-9-763---88-5--46-26-1--937-764812539158793264392456187473568921286941753519327846927635418835174692641289375 +---3----6746---21339--2-4588-9--7-4227349-8--4--81-739--4-8-69---2-7------------5528341976746958213391726458819637542273495861465812739154283697632579184987164325 +--5---9-18--7-9--36-4--38-71-983---4--2---------962--8-7--5--8991--287-6-4-69713-735286941821749563694513827169835274382174695457962318276351489913428756548697132 +8--5-6-27-7-8-14594--39--16---96-5-------3---9-328---16-1-58-4-----3--68---619-35819546327376821459452397816127964583568173294943285671631758942795432168284619735 +18----62-3-56---49--98----14--1-6-878-6---4---7-28-9---543-------1-28764--87--153187493625325617849649852371492136587816975432573284916754361298931528764268749153 +---736----7-82154---1---8-7--357-4--4--1----35--24-6-1-4-69---87---15-9-93-48----854736912379821546261954837613578429428169753597243681145692378786315294932487165 +6---384-2----2-7--8-54-1-96983-5--2------49-5--7-----3368-152--1-2--3--9-94--25-1679538412431629758825471396983157624216384975547296183368915247152743869794862531 +-35-842-----2--8-38-96---4----39-58---8--5--6--3-261-7--4571--8--1----7298-432--5135784269476219853829653741612397584798145326543826197264571938351968472987432615 +---3-----2-4--75-3-71-854--9--748-31----26---7-8-319--4-7--93-28---127545-2--3--8685394127294167583371285469956748231143926875728531946467859312839612754512473698 +783-16-2---4593--7----8-643-15---47-----7458--78-5---29---6----86-7--2-----13976-783416925624593817159287643315928476296374581478651392937862154861745239542139768 +27---1---46-83259-35-79-142--2---6------85-195--96----1-3---97---53---269----8---279451368461832597358796142892147653634285719517963284183624975745319826926578431 +-4-8-5--16------2-----29-74564-1283--9257314-7-----95-----8---51-62-7----28----1-247865391619734528385129674564912837892573146731648952973481265156297483428356719 +8-6--4--21-3--94-8--2-78163--9132-472-1-479------85---71--263-----4-----3-8--16-4876314592153269478942578163569132847281647935437985216714826359625493781398751624 +---524----5-36197-1-----3-5-2873------5-19-8--7-48---32--95-7----967-4-1--71----2793524816852361974146897325628735149435219687971486253214953768589672431367148592 +-2968--5--4-2---8---857-4---1-93---83---25-7----81--34-71---2-----749---8-5162--7129684753547293186638571492714936528386425971952817634471358269263749815895162347 +34--789-17-1-4--62---1--4--187-2-3-5--37---18------2---384--5-94-95-----2158-67--346278951751943862892165473187629345923754618564381297638417529479532186215896734 +-4------9--765--8--18-34---35------178-52143-62--47895--5--6------41-9-7-7----64-546182379237659184918734562354968721789521436621347895495876213862413957173295648 +9---8-237-5-4291-6281-----4--51-4-9--19---762-----7--15--94---3-9863-----43---8-9964581237357429186281376954725164398419853762836297541572948613198632475643715829 +95---386-6-3--8---8741-92--297-4-58-------4--5----2-97-3592-67-7-2-3--41-----73--951273864623458719874169235297641583318795426546382197135924678782536941469817352 +71-4-5-------72-4---2---8--831-67-94-74859-32---1---86-67---91-28--9-4-----5---7-716485329358972641942613857831267594674859132529134786467328915285791463193546278 +--------21--4--87-478-2--615-36-----6827-9--471-3---568-4-3-92----8----3-31-47-85396178542125463879478925361543612798682759134719384256864531927257896413931247685 +8937514-67--982--1-----4-9--841--2-7--------41624-38--6----9---218--79--4-93--6-2893751426746982531521634798384195267975826314162473859637249185218567943459318672 +5341-9--2-684-----7-16--8-4--------3--72--15-152-3-4-767--215-8-25-6-39----5----6534189672268473915791652834946715283387246159152938467679321548425867391813594726 +---5-3-12398--------2-64--89-6-271--251---4-74---9-2-6-248796-376-------8-92-6---647583912398712564512964378986427135251638497473195286124879653765341829839256741 +1-8-34---------71269--2---3-7-39--6-53-4---79---65-834------95-9-3----2775291-3-6128734695345869712697125483874392561536481279219657834461273958983546127752918346 +-3-68-1-7--72196--5--43-8--7---2-3168-1---4-23---96-----3-61----4-35-9--1-59-8--3932685147487219635516437829759824316861573492324196758293761584648352971175948263 +---4-2-36491--------658---1-659718-478-------1-98-6---5---9-6-8623---5-79-876-3--857412936491637285236589471365971824782354169149826753574293618623148597918765342 +-236------5------98---2-315-3-5--7-8-728---36--827-541-8615-4----9-8----34-7-61-2923615874157438269864927315431569728572841936698273541786152493219384657345796182 +---1238-7-27-493---4--8-2-9---465---1-6----32-98--2--5---97----5742-89-62-9-54---965123847827549361341786259732465198156897432498312675683971524574238916219654783 +291-6-53-346---1877----3-----2-51863538-42-1-61-8---25-57-2---1----8---69--------291768534346295187785413692472951863538642719619837425857326941124589376963174258 +--4---5811-3745-6-529--87---7-41---6--19-----935----178-7----42----32-78--2-746--764329581183745269529168734278413956641957823935286417857691342496532178312874695 +---8---5-4--915--21562348-7-18--29-4--------82796-81--9214--5--8-5--67-97--5-----392867451487915362156234897618352974543791628279648135921473586835126749764589213 +97-5-36148342-157---69-4-------4-2---85----6772---5-----8--7-------3679-3---5--42972583614834261579156974328619748253485312967723695481598427136241836795367159842 +--96-7---4-1---53---2--56949--4-6----3--98-7-8-417-9---9--6124-2--754-6---8-39-1-359647128461982537782315694975426381136598472824173956597861243213754869648239715 +4----69-5-92--3----3-49--2898--52-----68----9-1763---27-3-----1--832459---9178--4471286935892513476635497128984752613326841759517639842743965281168324597259178364 +----3-8---9--68-4-84----71365----4-242-5-1-----96-45----42--357287---6--9--7461-8512437869793168245846952713651893472428571936379624581164289357287315694935746128 +17----8---98-51------7---6-4---67-8----12-54---9---1--94681-3-7--5---6-221-5364-8174693825698251734532784961451967283763128549829345176946812357385479612217536498 +75-34----------9239--1-87----56-78-28-7--2--16-1---547---87-2-9-------863-829617-752349618184765923963128754435617892897452361621983547516874239279531486348296175 +-94-28--5--2-6---9-15--96------172--2479-5-1-861-------79----63-38-7--9-52-3----1694728135382561749715439628953617284247985316861243957179852463438176592526394871 +2-4--1-383----------85-3146--92--481---9--6--4-6--539--9-3-----6-31728591--4892--264791538315648972978523146539267481781934625426815397892356714643172859157489263 +4----97---18----9476---85-329-8-4--6--7-91-2---6---8-9354--29-------365-68291-4--423159768518376294769248513295834176847691325136527849354762981971483652682915437 +-----6-7---1732--85731486-9382--17----9--7---7-65--9-2--------663-8--2-12986-53--824956173961732458573148629382491765159267834746583912417329586635874291298615347 +-7-5---46-9-2-----------3--71---569856-892-7---96-72-5-2--687538-----4-----459821278531946396284517145976382712345698563892174489617235924168753851723469637459821 +--2--413--54---8-9-9--8-4-75--9--2-3--371-9-6--9-5---1------5721--82-----2-3-9618782694135654137829391582467517946283243718956869253741938461572176825394425379618 +2-65984-19-7-3----5-14-7293-1---596-35----7-44---8----1--6-4------81-34--9------6236598471947132685581467293712345968358926714469781532173654829625819347894273156 +25-3--6-78--4----2-93---84-14-8-35----294--1---5---4-3---6---756781----4531-94--8254381697816479352793526841147863529382945716965217483429638175678152934531794268 +-274359-----198---9-3-----53--68-2-----32-16--6-5-7-9---297---15-824--7-1---5--2-827435916456198732913762845391684257785329164264517398642973581538241679179856423 +-76-8934194----8561-3--69--4--86---2----3-----9-54-6137-43--2---5------43--124-7-576289341942713856183456927435861792621937485897542613714395268259678134368124579 +1792-85-----95---7435------5-28----48-137--2---7-4--8-9-8---46-6-3-9-8--72---6-5-179238546286954317435617298592861734841379625367542189958723461613495872724186953 +76-2-35---2-196--7-3-8-5-4-----62--5-9-5-48--5--93--64256--1-7-18-----36----29-5-768243591425196387931875642843762915697514823512938764256381479189457236374629158 +31927-5---58--32-92--59-83169--2---5----3---8--4------871---356542-8-19---61-----319278564458613279267594831693821745725439618184765923871942356542386197936157482 +136---------6-82--298-57-6---23----5-592-1--7-67--53---418---5-72--4---6-85----34136924578574638219298157463412376895359281647867495321941863752723549186685712934 +---975--19-812---35----------14-9--23-7--21-46-----9-8-89-514-7-4--6--19-3-79482-463975281978126543512843796851439672397682154624517938289351467745268319136794825 +43-65-182-1-7--34--86---5------2573---4-68-2-1-2----6-----9-6-3-4-2-6-97-695-7--4437659182915782346286341579698425731374168925152973468721894653543216897869537214 +74516-3-2--6----14-329----5-29-76----7--14-3--1----57-2-1-8----98-7-1--33--6-9-81745168392896235714132947865529376148678514239413892576261483957984751623357629481 +--56-3-42--72----1----7159----5-74---79-8-2--5-1--4-78--87--163--346----79-1--854815693742967245381324871596682517439479386215531924678248759163153468927796132854 +4632--1-----3--94-529-716---9----5-1-8-71--2-1-26-5--975-----16--61--8--9-85--4-3463298157871356942529471638397824561685719324142635789754983216236147895918562473 diff --git a/apps/sudoku/sudoku.hard.txt b/apps/sudoku/sudoku.hard.txt new file mode 100644 index 000000000..2a70aad75 --- /dev/null +++ b/apps/sudoku/sudoku.hard.txt @@ -0,0 +1,200 @@ +---15962-----2-89-95-86--7-8--9-634---35-81677---1295-12--845------91--6---2-----478159623361427895952863471815976342293548167746312958127684539534791286689235714 +29---3---------9456-89--213-2-8--57---7-9--36---47-82-53--6-18-8----469--4--8-3--294513768713628945658947213429836571187295436365471829532769184871354692946182357 +-9431827--------98---79-1-3-79--1--2-28---567-5--879-15-764------3-297--------314694318275731452698285796143379561482128934567456287931517643829843129756962875314 +4-7--1-322----------3-92157-8--2----1--3784--5-2614389--8-4-713----8-5--7-5--92-8457861932219753846863492157384925671196378425572614389928546713631287594745139268 +--58--937-769-------3-156845-4----6-6--3-48-5-8-15--2-9-74--2-6--25--3--35-----41145862937876943512293715684534287169621394875789156423917438256462571398358629741 +-65--84-77-8--1--61937-48-------56-46314---8---2-----13-4-57-69---8--2--9--1-35-8265938417748521396193764852879315624631472985452689731384257169517896243926143578 +-6-9-372---86-43---3-2---8-3--7-5-1-85-3-1----4--62--54--1296-3---478-----2---14-564983721278614359931257486326795814859341267147862935485129673613478592792536148 +---1-72-4-61432-79------31---837-4-1-39---758-17-4-9--------642-2-91---787-6-5---983157264561432879742896315658379421439261758217548936195783642326914587874625193 +8--3259-4--5----82---781---76-29-----8-5-46--9--61--2--9--5--7---784---9-4-93--51876325914135469782429781536763298145281574693954613827392156478517842369648937251 +--3-----7-9-16--8-----57-94936-781-2--4---5-675-6248-917------83-874---------1-6-583492617497163285612857394936578142824319576751624839179236458368745921245981763 +--789--1-5--243-6--9-61--45-8-97--3-7-43-1--99---64-----9-36---4-1----82--5-2-496647895213518243967293617845186972534754381629932564178829436751461759382375128496 +--9-568376-8--2-9-7-3--1-629-7-25--1----64-----173925-57--98--3---2-----3-6--7-28129456837658372194743981562967825341235164789481739256572698413894213675316547928 +-38-972----2-8493-9-63------9-----75-7-91--2-86-74----62---85--4-----19-5174-96-2138597264752684931946321758291863475374915826865742319629178543483256197517439682 +-7--4--36698--1-24--------97--45--9--4---2-----5-9-487362-14---9846-51-31--98-6--571249836698531724423867519736458291849172365215396487362714958984625173157983642 +-----4-----678--419--15-----2--98-65-58-4-----49561---2918-63---739-5--8-6541---2712634589536789241984152736127398465658247193349561827291876354473925618865413972 +85169-----9--73--16372-1-592---3-746--68------4--263---------3-7139--86---4-6-51-851694273492573681637281459289135746376849125145726398568417932713952864924368517 +281---------48-7--7435-6--8-7--1--6--586--1---3627--5--64----91-29-4---65-7--9-8-281937645695481732743526918972815463458693127136274859864752391329148576517369284 +8-791-4--5--8--1----146---53--72--1--2--846-----13-25----657---6-3-----8-14398-6-837915426546872193291463785365729814129584637478136259982657341653241978714398562 +9-3257-41--8-14-7------935-29--48-------3-2-735--2-1---3286--1-6--4-3----891--63-963257841528314976174689352291748563846531297357926184732865419615493728489172635 +3-6-9---75-98--162--2-------6--12-8----98-536-834-6921197-2-4-----5----92---49-7-316295847579834162842761395965312784421987536783456921197623458634578219258149673 +-8--14392192-584--3-49--8-1-61-8---4----9---37--------235---946847-3-21-6----2---586714392192358467374926851961283574458197623723465189235871946847639215619542738 +-1837---6-9--8----2-65-1-43--7----9--241-----8---4-372--27---85-8-45-637-458--21-518374926493286751276591843357628194924137568861945372632719485189452637745863219 +48--75--1--9------7--6-1-9426-------59-7-8--38173--95-3--1-7-699--4-6-8-65-8--417486975231139284675725631894263519748594768123817342956348127569971456382652893417 +--634----5--97-3-2-----2---45-23-1--89-6-47--3617-5-8--1--674-574--2----62-453---276341598584976312139582647457238169892614753361795284913867425745129836628453971 +--1-6495-5-6-931---925-----7834-92-1-4----79-12---68--26-34----3--97--1-9------38831264957576893124492517386783459261645182793129736845268341579354978612917625438 +-2-56--4----7-8-239-------8-86-----44-938---------6-5-3-----7-5-781534-25928-46-1823569147165748923947231568286915374459387216731426859314692785678153492592874631 +3--65--7----73-58--5--412----712---88--4--7--4-697-1--2-3-----4-71394-2----286---328659471164732589759841236597123648812465793436978152283517964671394825945286317 +8---2-6-1-5-9---4227-----59--7--5-686--1-4-355--7---1---18-9---------487-8--56193894523671156987342273641859417235968628194735539768214341879526965312487782456193 +4-2-----5--84-79--9-78--6-328-746-3--94-5--7-7-691-42---9164-----------1--3-892-4432691785568437912917825643281746539394258176756913428829164357645372891173589264 +42-16--75-8-5-4-6-651-79-3--943--5-7------2--2154-----9--64-3-15-69----4---75-8--423168975789534162651279438894326517367815249215497683978642351536981724142753896 +6-8--259------68-21--7-56344---------35--19--9-6-4-1538-351--292----3----74-2-3-1648132597357496812192785634481359276735261948926847153863514729219673485574928361 +-2-6-359-5--489-6---71-2-3-2---96----1-2-7-8-7-983-2----2-68---9-3---41---5--4629428673591531489762697152834284596173316247985759831246142968357963725418875314629 +-2-6-4--35--39--7-13-75------124-5---4-58-96--5--6--1----129-----6---72-2--8764-5729614853564398172138752649691247538342581967857963214475129386986435721213876495 +-5-8---973781--46--294-78-38-7--9--6--6-139-8----5-7-496--74--1----2----732-----9654832197378195462129467853817249536546713928293658714965374281481926375732581649 +-31--246--4---------67-41928--4------2-168--3-94253786---8----9-19--78-4--83--621931582467247916538586734192863479215725168943194253786652841379319627854478395621 +--7--3-29-48-----62-9-6458775-----4--2-84--5----65--93----1-9-4--24-531--143-62--167583429548729136239164587756931842923847651481652793375218964692475318814396275 +-47---3---91843-76-856-14294----5----1-----65---36-1-21--45--9--6----2--93-7-6---647529381291843576385671429426195738713284965859367142178452693564938217932716854 +--1-35-7-364-729------4----9--3---64523---79-47695-8-31----4-87--7---2---8-716-4-891635472364172958752849136918327564523468791476951823135294687647583219289716345 +-9--16--3--542--1--81-39---8---549----9--2--8--4-976-2---685----5-27349-2-----3-5492716853635428719781539264826354971379162548514897632943685127158273496267941385 +-9-2-------19------24-57-9168-7-41----91-32-6--76-5-481--469-83-7--3-9--9-6---4-5795216834361948527824357691683724159549183276217695348152469783478531962936872415 +-84---2--2-9-78------4---1----86-73--3--14-2-9-----8---687513-27-----1-619328-5-4384195267219678453675423918541862739837914625926537841468751392752349186193286574 +1893-4---6-71--49---39-6-7--64------7-5---6-939-6-2745----192-8572------9----536-189374526657128493243956871864597132725431689391682745436719258572863914918245367 +89--3--21-4-81----72194----4---------17--9----852---471-965---8-7412---32-87936--896537421543812796721946835462375189317489562985261347139654278674128953258793614 +8--3912-------68--6-1-85--4-8----5----3--21985-68493721-295---3--5------9--6134-5854391267397426851621785934289137546743562198516849372162954783435278619978613425 +416-29--3---7---547536----9--4---9-169-3-14----829--6-84-1--7-5-21---39-3--9----8416529873982713654753648219274865931695371482138294567849136725521487396367952148 +--58--743--793----86-4--9522-4--95-8-86-5--1----2-8-9---23-71-9--81--4------84-26195826743427935861863471952274619538986753214351248697542367189638192475719584326 +-691--28--17--5-9--2-9--5---9435----1-27----3-83-9-4--246-7--19875-----------274-569137284417825396328964571794356128152748963683291457246573819875419632931682745 +-16--78----3---25-4283-56-1-6743-----4-52--1--5-----481---7359-6-59-----79--541--516247839973186254428395671867431925349528716251769348184673592635912487792854163 +6-21--4-33-79---589-5-836--531--6-82-2--9-1-----3-15-71--6-----4---1-----7954--16682157493317964258945283671531476982726895134894321567158632749463719825279548316 +7--8-6----6157---3-593---76----6-41-62--1--3-19--85---9-61243-8-----9-62--5-38--4732896541461572983859341276587263419624917835193485627976124358348759162215638794 +--7-63-5-------4728-59-2----56-4---3-31---985-8--51-64---5-6-47------6-1-6271453-127463859693185472845972316756849123431627985289351764318596247574238691962714538 +32-1-----7-42--1-31967-85--567-9-4-14--5---67------9--65--2--89---6--2---42-573-6325149678784265193196738542567893421439512867218476935651324789973681254842957316 +8569-2-74------89--79---5-67-83--6-9---4-87136--7-94--9-4--5--7------265-12-37---856912374423576891179843526748321659295468713631759482964285137387194265512637948 +8----------73-89416-1--9-784-89567239--1726---2-8-------26--197---2--4--1-4--38-2893417265257368941641529378418956723935172684726834519382645197579281436164793852 +---2-4-31764------3---95-7-9-6-381--123---58---5-6-39-6-73-9----98------53-78694-859274631764813259312695478976538124123947586485162397647329815298451763531786942 +96-175---13--9----2---6317---651-----7-83-59------9---6523-7--484-6-13--71-95-2--964175823137298465285463179396512748471836592528749631652387914849621357713954286 +--8-72-59-9-615-7-3---48-2--8-5-7-----4-83-6-53-26---89----158725-----418--7-6---618372459492615873375948126186597234724183965539264718963421587257839641841756392 +4---175---7825--1--1-8-6-----7-412---3-5986--1---6283---16-5----82---49---3--9168426917583378254916519836742867341259234598671195762834941685327682173495753429168 +4-5-386--3--174--58---96-2---681--421---629-----4-3--6---3-1-6-9-7----84643--7-5-495238617362174895871596423736819542154762938289453176528341769917625384643987251 +-6-93-8----4-27-3--5368----5--74---6--62--5----716-2-92-----4-8-4-812-67---459---762931845984527631153684792529748316816293574437165289291376458345812967678459123 +1-27598--5-82--379-7--382-53--82495----391786--9-6--------4----7-------32--6-5--8132759864548216379976438215367824951425391786819567432681943527754182693293675148 +-965-8----8-----7---124---652-----9-43-8-162716-3298-5--2--4----1----4-8---98-71-796518234284693571351247986528476193439851627167329845872164359915732468643985712 +-7--85-2---69-45---35-72------863----6-4217-94------62--9-17-48--7-4--3-3---96--7974185623826934571135672894792863415563421789481759362659317248217548936348296157 +-15-37-8---3-486---6---1-3--9--25--32--81--4-----93-26-49---1-----564---3-8179--4915637482723948651864251937496725813237816549581493726649382175172564398358179264 +-4192--6-532-4---9-76-1-8--15-6--2-8-68-5--7-2-4-----6---37-1-24-5---6----34629--841927563532846719976513824157634298368259471294781356689375142425198637713462985 +6--8-2-5-----3---29256--8---14-87269---12-347-7-9-6-1---6------3-2-1-9764-72----5631892754748531692925674831514387269869125347273946518186759423352418976497263185 +-9-5-----7---8--34---67-52-9371-485--6-3-2---2-57-86135-48------89----65----3-4--892543176756281934413679528937164852168352749245798613574826391389417265621935487 +-1--89542--6--21-8-98--136--69--3-----2---7--1---9-2566-43-89-5-7--1-----31-25--4317689542456732198298541367769253481582164739143897256624378915975416823831925674 +-671-943513----9---4-8--67-----9586-7---31-5-5-4----1-21-98---7-7-51--28-----21-6867129435135647982942853671321795864786431259594268713213986547679514328458372196 +8--------5-463-9-----7583--9-7--62-3--3-256--1-----4-5-458-37-2-2-1--53--9-572-64836249157574631928219758346957416283483925671162387495645893712728164539391572864 +5--329-47----81---3-9-475--8-2--36-4---4------37-962--9---783622-3--54-86-8--4--9561329847724581936389647521852713694196452783437896215945178362213965478678234159 +--9-5241----7------72--4-9371-495--6----38-----6-71-54294-13--5-37--6-49-5---7-32869352417341769528572184693713495286425638971986271354294813765137526849658947132 +----3859-827-------9-1-6-2-27--91---4-1-------69427-8171-9-4--5953----466--7---19146238597827549163395176428278391654431685972569427381712964835953812746684753219 +29876---34-5-8-----16-4-5-8963--28-1--1-3-69---------214-6-39-53-9--427-----9---4298765413435281769716349528963572841521438697874916352147623985389154276652897134 +81-56-2--4-539-7--7-6142--3--8------97-6--18-15---4---56148-----8-75-----47-2-56-813567294425398716796142853638219475974635182152874639561483927289756341347921568 +-7-1-8924--85-276---4-9351----3-----3-9-861------59--21-582--4-----3-85----91523-573168924918542763624793518852371496349286175761459382135827649297634851486915237 +8--9--216--6-3-----2-8-6-9-691-875-435746-----4-1-9--7------9----26--75-179-4-63-834975216916234875725816493691387524357462189248159367563721948482693751179548632 +83412-5-7156-47----7-3-8--19----415-318-7-46-------3---9-4-2-3-4---6------2--3984834126597156947823279358641927634158318275469645891372591482736483769215762513984 +--8-76--44----2-8-2-5-81-6-----9843--3-62--7-9---358---862197-----547---7-9-----2318976254467352189295481367652798431831624975974135826586219743123547698749863512 +21-7---8--75-9-6---96---47---1-4--6--63-15-2--82--6--4548----------89--11396-28--214763985375894612896521473751248369463915728982376154548137296627489531139652847 +--4-53-29---1-----1-3--26-4--7-192-5----68---91-2457--5----13-6432-965--6-1--74-2784653129269174853153982674847319265325768941916245738578421396432896517691537482 +2-7--51-4-54--1---9613-78---89-5--36-----95--52-78-4-9--2--8-97------6--798-6-2-1237895164854621973961347825189254736476139582523786419642518397315972648798463251 +5--39--2--3---1-----9-2-543------2--624--731--5--3-68-7--24---6861-73---2436-98-7586394721432751968179826543318465279624987315957132684795248136861573492243619857 +96---52-----7---1--81---53-----91-2-13-27------9---6---12657-49643-18-52---3---68967135284354782916281469537476591823138276495529843671812657349643918752795324168 +4-31-297617--------69---1-4--4--631-926----------542-8-3-4-1-9--915--74-8453-7---453182976178649532269735184584276319926813457317954268732461895691528743845397621 +134-8--26698---5475----6-----1-2467884-7--2-1267-91--4-25-1-4------7-8--3--------134587926698132547572946183951324678843765291267891354725618439419273865386459712 +6--9-3-85-3--567-----84---6-9--67-5--4-381--228--946--17-----98---43--6-468-1--2-614973285832156749759842316391267854546381972287594631173625498925438167468719523 +8-574-621-125---7-67----945-2-6318---86--2-3-9-------67---69152-6--54--3----2----895743621412596378673218945524631897186972534937485216748369152269154783351827469 +---3--4-656-2---7-8-4-67--36----82--4---321-9---45--689-----31-7--8196---567438--271395486563284971894167523615978234487632159329451768948526317732819645156743892 +4-----8--5----4296--1-287-47--4-----264-9-5--935-876411-7--6982----7------9-52-67472639815583714296691528734718465329264193578935287641157346982826971453349852167 +-817--4-97-49-----5691-2--3613-5-9-8--83--16---------53-6-7-52-87--316-4---6----7281763459734985216569142783613254978458397162927816345396478521872531694145629837 +165---3----4-6-295-8-3547-193----4-664-79------843-9--8--1-3-4------21--41----572165927384374861295289354761937218456641795823528436917852173649796542138413689572 +---865---49-213-5-3-5---2--9---546----6--2--98-2-91--4----39-67-7-42---5--3-78-9-721865943498213756365947281917354628546782319832691574284539167179426835653178492 +--267-13---41--5------54-82--94--765--73-6---48-5--3292-5-3-94--48--9--1---24---3952678134864123597713954682139482765527396418486517329275831946348769251691245873 +--8136-455-38----96-15-9--7--749-618-------528-6--7-941-59-3--6------9--46---1-83798136245543872169621549837237495618914368752856217394175983426382654971469721583 +328----49-4-----36-9623--7-83----9--56-48---2--4------48--7--239-3-6--516-2--1798328756149745918236196234875837125964569487312214693587481579623973862451652341798 +5-67-2493-29-----7--3--1-5634-----2----47--61-5-29--4----8--6-2--5-2418--82-175--516782493429536817873941256347168925298475361651293748134859672765324189982617534 +-9---3-4--6--9253-4---869----9-75-1--8-63---7-74-19-----83216-9---548---3-----18-192753846867492531453186972639275418581634297274819365748321659916548723325967184 +---2-54--457-86--2923-------4-3---8--62--83---784-9-6--915----86-4-1--2--85----13816235479457986132923741856149362587562178394378459261791523648634817925285694713 +8--3-5796-----62-46-4--2-157---------95--8--11-6-7-9582----9---4-958-12--37-2-8-9812345796953716284674892315748951632395268471126473958281639547469587123537124869 +-2---1635--7245-98851----4--7--24-6-1-2-96---6-4----21---3---8-7--48-2--2-8---953429871635367245198851963742573124869182596374694738521916352487735489216248617953 +937------6--9--45----61-3-81682-4---57---126--4-5-6-7--25------79----5-64-63-5729937458612681923457254617398168274935579831264342596871825769143793142586416385729 +8634-5-915-9261-78----3--4635--92-----7---6-----5-7--94-5---1-3----2---567-1--9--863475291549261378721839546354692817917348652286517439495786123138924765672153984 +--5912-7-6-3857294-2--6--------2--3-2---7-5193-1--4-629---46351--6------1-7--59-6845912673613857294729463185598621437264378519371594862982746351456139728137285946 +-65--97-3-27--814--4871---5--3-9----28--3459---9--5---7945--61-6---8---9---9-72-4165249783927358146348716925573892461286134597419675832794523618652481379831967254 +-1---2---925---6317435--28---48-35622869-43--35--6-4-88-14----3---6----5-7-------618392754925748631743516289194873562286954317357261498861425973439687125572139846 +--6452--7-75-86-1---8-193--561-2-7---29---8-5---64-1-----56---1--4-31-9--1-8-45-3136452987975386412248719356561928734429173865387645129893567241754231698612894573 +9--2--567-4-5891-3521-----8-86---2-94--89---6-9263---------7--1--4-18-9--19---735938241567647589123521763948386174259475892316192635874263957481754318692819426735 +264-398--8-3--4-1-51---893-7------4-421-9---8-----519---6-4258-----8-7--9-25-3-61264139875893754216517268934759816342421397658638425197176942583345681729982573461 +--135-8-2--58--6--6--19---58-----9-4-9-438-51---962----6754------9-81-7--5-27-4--971356842435827619682194735823715964796438251514962387367549128249681573158273496 +-----35-662-1--8-7-------2---4639-188--47--539--51-6-2---32-165---85-2--51--9-38-147283596629145837385967421254639718861472953973518642798324165436851279512796384 +3512-4--6-89--5---74---98-5--------1-7---643-463-1-5-79-746-3-8-36-9-12------3--9351284976689175243742639815295347681178956432463812597927461358536798124814523769 +--------5-3-451----8-6-39-132--6-4-819------7-6--123--9-6124-8-24-53-19--137---2-471289635639451872582673941325967418198345267764812359956124783247538196813796524 +--1-43----78--9-5-6397-814--4-96-----85---6-1-6--7-4-38-4---2--52---7-647---24-15251643789478219356639758142347961528985432671162875493814596237523187964796324815 +----83-----6-91-2591-245-6--89--6-42-5---9-78742-18-5---4-572-1---9------97--2-84275683419436791825918245763189576342653429178742318956364857291821964537597132684 +-97---21-1-5-9---------3--5----286-18----935--7--1-----2-63----73854-1-96-198-432397854216185296743264173985543728691812469357976315824429631578738542169651987432 +-17-2-4------5-6--3--------758-92--4-2--748566-45--7-2243-6--781----8---869---145517826439492753681386419527758692314921374856634581792243165978175948263869237145 +-2------59-7-86------9-28---93---7-42-54----8----6-9------7-53--8965412-5713-948-428731695937586241156942873893215764265497318714863952642178539389654127571329486 +7-94----243-682----129376-49---1-573-8---3---1-35---9-3----526-------9---4-27938-769451832435682719812937654926814573584793126173526498398145267257368941641279385 +-41-26---------792--785-1--8-239751--------83----819-74--13-8-95-3---4611-89----5941726358685413792237859146862397514719542683354681927426135879593278461178964235 +8-695----1---32-8---9---7---18643-59-53---6---2419-378--1----92----691-73--2-----876951423145732986239486715718643259953827641624195378561374892482569137397218564 +7---3-1596-9--27-8----7---6--8------9-3--581-1---28965-7--8------5197--38-6453271782634159639512748514879326258961437963745812147328965371286594425197683896453271 +78-542-63---1---95135-98-72-56-2-7-----4----889----2-16-----5---187-4-------86--7789542163264137895135698472456821739321479658897365241672913584918754326543286917 +7462138-5932--6--78------2-6--7392--2----5-----1-285-9--738-9-6--------81-85973--746213895932856417815974623654739281289165734371428569427381956593642178168597342 +1-----57--548-71--3--25---4---6---19471-25-8-8964---5-72----8-5--85---3--137--69-162349578954867123387251964235678419471925386896413257729136845648592731513784692 +--9--48676-3---1-4--87-5-----2-183--9--5467---8--736-9-1--825--2-635---88--6-7---529134867673829154148765923762918345931546782485273619317482596296351478854697231 +-2--319---8-576--4-64-82-1--37---2-6---8-51--618--74----125-6-9-5--19-3----6-8--1725431968189576324364982517537194286942865173618327495871253649456719832293648751 +9---36-2--6572---3-3-5-4---3---47-58-8-215-4---6-93-7---8--1534-57----91--34-2---974136825865729413231584769312647958789215346546893172628971534457368291193452687 +-1--46237-36--8--1-72--58-6-21-845------69----5-271-84-67--23-8---8-----2-4-137--815946237436728951972135846621384579748569123359271684567492318193857462284613795 +--4-5---2-5---4-73--3-28-415-6----94--76--32-4---9--687--4-3219------857-2--79---194357682258164973673928541516832794987641325432795168765483219349216857821579436 +----123-73--46-5---1--38--2--2-54-7--7---62---68-294---51----6-2-4691--5---875---846512397329467581517938642932154876475386219168729453751243968284691735693875124 +-----1---5--9-76-86-----7139-7--4---8--6--27-2-63-5-8-76--2---43-279--61-89-5-327473861952521937648698542713957284136834619275216375489765123894342798561189456327 +1--697-25-6----1-7---431----3--15--2--2--63----5-296-43-8-72-----156--8-2---847--183697425469258137527431968634715892972846351815329674398172546741563289256984713 +6-597124-9-83-----1-2-84369-2--1--954--7-----31----48--9----5-----2-7-342---45---635971248948362157172584369826413795459728613317659482794836521561297834283145976 +3-51--249-12--9---------167--3--651--97-5-43--6--3-9-----68-32--2-3--78-8---1--95375168249612749853948523167483976512297851436561432978759684321126395784834217695 +6-8-12--5--15489-22--------4-21795365--6--817-7----2--8-42-7--9---4--7----78516--648912375731548962259763481482179536593624817176385294864237159315496728927851643 +1------98---479-----92185-3-648-5----9-13-6----56-7-8--5---1-4-4--9-3--5-3-5-2-17127356498583479126649218573264895731798134652315627984852761349471983265936542817 +-2-3-6-4----5-----3514-89--9---3--15638---49-51469-7-3-4----8----7241-5-2----5-74729316548486579231351428967972834615638157492514692783145763829897241356263985174 +--91687---15---6----8457-2989-2-4-----3-8-9--6-153-4--5--97-8-4-7---329-9-4--5---249168753715392648368457129897214536453786912621539487532971864176843295984625371 +25-8---9----4---3---7-------845-93--9--134-58315--8-69879-51-4-461283-----2-----1253876194698412537147395826784569312926134758315728469879651243461283975532947681 +67-3----81------458524-17-6-4----82--2--54-7-36--12-----713--94-9324---74-6--9---674325918139687245852491736745963821921854673368712459287136594593248167416579382 +9-351---27-----------947--5--56-9--12-4--1-568------93-2-49613--39-75-64-6--8-5-9943518672751362948682947315375629481294831756816754293528496137139275864467183529 +---4------1------2-8--65--7--127-8-683-6917--76---8219-2-84796-9--5--------932175357429681416783592289165347591274836832691754764358219125847963973516428648932175 +6-7-14-5-2----6-1---1-35--28---971------8129--9-56--3-3-8-----6-156483-----723---687214953253976418941835672832497165576381294194562837328159746715648329469723581 +-269-85-----7--2-8---6217-93---86951-8--924-3-5-17-6-2-----7----1784---6---21--9-726938514139754268845621739372486951681592473954173682298367145517849326463215897 +-52974--6-71-86-5-43--21-9-58---234---3------14-7-----214-37---3---15---7-5-9-21-852974136971386452436521897587162349623849571149753628214637985398215764765498213 +----8----815-936--2---14--9--7925--89-----3---2---8-9758964-71--6-1---85143---9-6394786251815293674276514839637925148958471362421368597589642713762139485143857926 +-4329--17-7--8-23--6-7315-48------436-15---72--23-7-5----913-2-9--------3-4-52-6-543296817179485236268731594857129643631548972492367158786913425925674381314852769 +------4891-3--827678-6-----3--4--81--4--3--6-96--1-32--7---359---5-8-6-1----5473-526371489193548276784629153352496817841732965967815324478163592235987641619254738 +---6----4----1---616-48-37-59---1268--67--5--3-8-26-----19-2-8798--7--322-4-6--51859637124743215896162489375597341268426798513318526749631952487985174632274863951 +82-6-4--39415-38--65--97--1---7-----5---32-79--4-69---47-956----1-34--5636--7----827614593941523867653897421192785634586432179734169285478956312219348756365271948 +-6---5---7--6-91-5-4-321--64287635-9613--42---9-----6-------9--2--93-4-197-152--3169475832732689145845321796428763519613594278597218364351846927286937451974152683 +2-7-64-3-1-68-9-5-458-13--7----9-----4-6-8-----13-298-9-4186---6-39-----5--43-16-297564831136879254458213697825791346349658712761342985974186523613925478582437169 +73--2--9-2-51----81-8----26---9-17--471-83--9659--------76---8-8-47-5-3-9-3--86--736824591245196378198357426382961745471583269659472813527639184864715932913248657 +-9-2134-7---968---3------92--714--386--79---4--43---6--6542------9-375---4-85--2-596213487472968315381574692957146238638792154214385769165429873829637541743851926 +----8--1---6-4283-9-23-76-51-----4-------395-425-9---88-7--45--35---879-264-79-8-743685219516942837982317645139856472678423951425791368897134526351268794264579183 +8--3---5-7-4-5-3--1-586--7-6-92----55-2----93-78--9-4-281-75--4463---------42-8--896347251724951368135862479619234785542786193378519642281675934463198527957423816 +--2-96--1------3824-17-3----4--158-9-19-8-6---65---174-93258-16------59----1-92-8532896741976541382481723965347615829219487653865932174793258416128364597654179238 +-23--4--7--9-7--4--75-3--969512--7-3642-----------9-21-867---1-39--2-8---1748----123964587869571342475832196951248763642317958738659421586793214394126875217485639 +23---6-8-6-9-5-7--5-7---16-8-37----17-492--3---2-1--7-4253-78-----58---2198------231476589649158723587239164853764291714925638962813475425397816376581942198642357 +5--3-4--7---78-5627-2-15384-4-1-8--9----6-8--8394---1---4-------68-7-435-258--9--586324197413789562792615384647138259251967843839452716174593628968271435325846971 +1-826-5379-3----4-2-54836-9--6----7--2--31--5-5469------2---1-6----4672--3-1-----148269537963517248275483619316854972829731465754692381492378156581946723637125894 +---539-----9--71-4-67----25---9-3-71---81----1-5-748936--3-17-84-8726---7-14--3--214539687589267134367148925846953271973812456125674893652391748438726519791485362 +--6-824-9--96-4---7-2359--1--------3--1--825--3-5219-821-86-5-4-6-1-537---5-----6156782439389614725742359681528976143691438257437521968213867594864195372975243816 +429586------9----557-132-6-2--754-811-762-4--645--1-72--6----4---2-79-1----3-----429586137361947825578132964293754681187623459645891372956218743832479516714365298 +-8--65---627-81----15-3--6245---2-78--8------76-1-----87--26-3-1-6-49-5-5-23179--384265791627981543915734862451692378298473615763158429879526134136849257542317986 +7--69-8---5-----1-83-4-5----64----3--295-7168-872634-5-7----5-96----9------35--71742691853956832714831475926564918237329547168187263495473126589615789342298354671 +6---9517213-8-----5--7--8632-5----1--7-95--4---16-27-53-82--4-14--5--6---56----29684395172137826594529714863265473918873951246941682735398267451412539687756148329 +81----9---4-95-1-----16-2-7--8--74-2-95-----64-26-9518---3---29-39-76-4---4-9137-816723954247958163953164287368517492195482736472639518781345629539276841624891375 +17243---5------3---53-1-6-25941687-36--2951-----3---9-7--9-----3-9-4-2-72156----9172436985968752314453819672594168723637295148821374596746923851389541267215687439 +-36-582-77-5-3--14---7--3--587-4-6-96--5---78------4--86-3--9-22-39-----9748-15--136458297795236814428719356587142639642593178319687425861375942253964781974821563 +------6913-251------9-47-2--27--6--4-48---532-3--82-76---27--69-7196824-------7-8754823691362519487819647325927356814648791532135482976483275169571968243296134758 +389-145----4-8569356-9--4-8-7-----------9---68-2-4---5745-6-38-136---952-2---3---389614527214785693567932418673521849451897236892346175745269381136478952928153764 +----3--2-8-47-5---35------4--8-----5-9-2-3-4----15--9798254-3-6--7---1-251-6724-9671439528824715963359826714148967235795283641236154897982541376467398152513672489 +76-53---8-----6------79-2-----987-62----6--9398--23-1---43-81273--2-9-541--67--89761532948239846571845791236513987462427165893986423715694358127378219654152674389 +--7----86--9817--334-296--12-13-96---34-5--9-----6-3-2--26-57-8--3--1--5---42-13-127543986569817423348296571271389654634152897895764312912635748483971265756428139 +-96-43-----1---83---3-21-7--679----8-4-----123821-47-67--49--519-531---761---5---896743125271569834453821679167932548549687312382154796738496251925318467614275983 +8-6-14--3-178-------3-65-8176-45----4--19--3-1-----24-9245-13-7-5-----1937---6--2896214573517839624243765981762453198485192736139678245924581367658327419371946852 +2-194---8-7--82-4-8--1-3---1-9----76--5--6183--83-4---5--461-3---2-78-9--8--39-15251947368973682541846153927139825476425796183768314259597461832312578694684239715 +-----37-6--12-4398-73--645--35-8-14994---15----8--------6--9---28--6-9-1-9741--65429853716561274398873196452635782149942631587718945623156329874284567931397418265 +2-17-------3-89-72-78-25--3-2----65--5-24--3-81-59----6459-23-19------2413---8--6291734865563189472478625913324817659759246138816593247645972381987361524132458796 +--3---21---7-25--929-1-83--5-1---8-2-8---2-7-37---146-648--9-2------4-3613925--8-453697218817325649296148357561473892984562173372981465648739521725814936139256784 +1-8--5-4372----59---3--2--72-5---4---6--293--4--5-7-26--729-654-84--1-----2--6781198675243726134598543982167275863419861429375439517826317298654684751932952346781 +15-----872-97--64---65--1--5-7-----44--1-735--3-85---6--53--291--1-85473-942-----153462987289713645746598132517639824468127359932854716875346291621985473394271568 +712-96-844--2-7--683641------51--86-627-4-31--------7-5--9-17----1-3-----9-7--251712396584459287136836415927945173862627849315183652479568921743271534698394768251 +-54--38277---9--4-8-12-7---6-27--3-43---529-8-859--2-1---3--7------7-6---7386--19954613827726598143831247596692781354317452968485936271169324785548179632273865419 +-1-6-9--8------571-8453----4--2-87-962----83489---76-----98-1-795-712-86------29-512679348369824571784531962435268719627195834891347625246983157953712486178456293 +2--4--95---1--64-84-7---6-1-7--1-2-55---891-31----7--9--215-396-9--62---------782286431957951276438437895621879314265524689173163527849742158396398762514615943782 +639---7-4-4----2-927-93---54---------2864-3---96----7-3-2--16579-72--1-8-645--9-3639852714845176239271934865413729586728645391596318472382491657957263148164587923 +------1486-1--7---29--1-675---38-9-6--6-9-4-3-3-1---279----82-1--89--7--4-72--5-9375629148681547392294813675742385916816792453539164827953478261128956734467231589 +92-64--37--8--5---5-43-1-9--5---73217-24-----1-------8--57-69132--1---656-75--2-4921648537378295146564371892459867321782413659136952478845726913293184765617539284 +--91-43--3-17-56--745--912-6--9-723-------81--32--69574-35-17----------35--27-49-869124375321785649745639128658917234974352816132846957493561782217498563586273491 +3-65--82-9--6--37-27831--9---516-98----43----16-928-5------6---6-78--23---279-1-8316579824954682371278314596425167983789435612163928457831256749697841235542793168 +4--821--7---5---1-2197645-3--------57389-52---25--78-45-1--93-88724--1--3--1-----453821697687593412219764583146382975738945261925617834561279348872436159394158726 +53----6-7---416---4--5--82-2-5--8-1-9-8375-----32-195-----29------1-42-56-285-194531982647827416539496537821245698713918375462763241958154729386389164275672853194 +-135-4--74-8-1------76-3-14-4----95-38--56----5--42-7-92546-7-86------4287-3----9213594687468217395597683214742138956389756421156942873925461738631879542874325169 +6--432-5---198--7--8-57-63---8-25---3-7---49---6-4-5838---53----9-81--2-1-32-78--679432158531986274482571639948325761357168492216749583824653917795814326163297845 +19-86--2--3--9--8-8--72---3---48-35---59-2-7--4-51-8--47------9---371---2-86497--194863527732195684856724913921487356685932471347516892473258169569371248218649735 +----718---36-54129184-32-67-----69--5-13----2-672-8----5-1-----6-8---39------3-56925671834736854129184932567842516973591347682367298415253169748678425391419783256 +231----------9--15985--17-6-16-3---7-786---92--97---3-69-1--4---42--7-5--574-3---231576984764892315985341726516239847378614592429758631693125478842967153157483269 diff --git a/apps/sudoku/sudoku.medium.txt b/apps/sudoku/sudoku.medium.txt new file mode 100644 index 000000000..bb9b3a6c6 --- /dev/null +++ b/apps/sudoku/sudoku.medium.txt @@ -0,0 +1,200 @@ +52-9647-1--4---9-5879-216-3--8---2--7--39--1-----5247------3-9--8124----23----1--523964781614837925879521643158476239742398516396152478465713892981245367237689154 +-4-9-3--57--28-9--96-5-4-----67-8-4-4----2--68--4-1-32---637----7-12548---2----57248913765753286914961574328326758149415392876897461532584637291679125483132849657 +--92---58-1---742--62---17---8-4531---1--65--6---1-89--9-18-7355---79---------964479231658815967423362458179928745316731896542654312897296184735543679281187523964 +16-2-4----5-39-6--------572--186-9-7-83---146-96-7---3-2978536--------98---9-67-5167254839852397614934618572241863957783529146596471283429785361675132498318946725 +87--541-22----975-6--127-38--9---8-7-5-27-3---16-3-2-5-875-36----4---------7415--873654192241389756695127438329415867458276319716938245187593624534862971962741583 +9---851-48-4-129-----4--68--75-----8--983---5---52--163-8----2-7----1-6969-2-8573926785134834612957517493682275164398169837245483529716358976421742351869691248573 +---83-69--7-----8---6-245-----4--2--4-8----5-75--98---62758--148-3912-65-9-----23214835697375169482986724531139456278468271359752398146627583914843912765591647823 +53-7-91--78-6--9---6-38574-37-9-85--4-5--386---------965---149-------27--1-49-635532749186784612953169385742371968524495123867826574319657231498943856271218497635 +3-4-682592----134-58----6--87-1-6--44--8-9-71----7-8-3-92----8--4-58--9----69-13-314768259267951348589243617875136924436829571921475863692317485143582796758694132 +-895-4--31--78-9--3------485269---8----6--23-943-78-5---58---1-47----8-5-314---26289564173154783962367192548526931487718645239943278651695827314472316895831459726 +82--349----529--3--9-7-8---2--95--4--1-863-7---947-18-9--3-7---48----65-1--6--798821534967745296831693718524278951346514863279369472185956387412487129653132645798 +----5--6-93----4-86-4--3----8-2-5---1596-7-344-23-1587-9---4-----1-3-6-5----18-42728459163935176428614823759387245916159687234462391587293564871841732695576918342 +91-38----6-8-----1-----6-5--3----7-54598-16-28-72531-4-9------8---7-8-43--456--1-915387426648925371273146859132694785459871632867253194791432568526718943384569217 +287-43-1---1--9-839-3--5-725---94-21----36----94271-5----9-----8-9--2-377---182-4287643915651729483943185672576894321128536749394271856432957168819462537765318294 +3-6---21-----9--6-48---25------1--436-5249-787416-3-2516-95-------8-6-5---8---4--356478219217395864489162537892517643635249178741683925163954782974826351528731496 +--958--1-2--463-7--8-71-26--5-89--3-9-63-18--8---76-----2-4-7866-1---45---8-37---769582314215463978483719265157894632926351847834276591392145786671928453548637129 +-----1-----235---43547-2-1-2-38-7--9-98-----7517--46-392-5-834--4516--9------9--5679481532182356974354792816263817459498635127517924683926578341745163298831249765 +39----24--584---6-14--9-3--9753-86--621----------69--573--51-8-86---3--25---2--3-396185247258437961147692358975318624621574893483269175732951486869743512514826739 +--869--722-1--7----7952---8-2----45-91--65----5--32-8-4352-68-16------2318-9----4548691372261387945379524618823719456914865237756432189435276891697148523182953764 +4-7----25--8-7-3-12----6---15---4---93-761-8278-25-149--1----3----6-82-48--32----467139825598472361213586497152894673934761582786253149621945738379618254845327916 +7--4-8------27-8-6--1----4-15--6----34-912-7897-8-51638---2------7--94-16-9----85765498312493271856281356947158763294346912578972845163814527639537689421629134785 +519----24--2-5-----4-23---8--64-38-----1-6-477-4----36--3---972965--74--2-1349-8-519768324832954761647231598126473859358196247794582136483615972965827413271349685 +--5-876--4--2-6--93-64-9-----47----3--81-4-27-3-8-5-4----523----7-----955--97148-925387614487216539316459278194762853658134927732895146849523761271648395563971482 +7-1-3---48-365-7--6--4--3---76--21--5-29---3-3-9---24-968-73-1----19---6154------791238564843659721625417389476382195582941637319765248968573412237194856154826973 +---91-4---8-5--37-41-3-7596----65-1-1-9-7--6-6-4---83--4812---7-617---282-----1-3735916482986542371412387596823465719159873264674291835348129657561734928297658143 +--83-15--6-529----9-------78-----91----6-9-78--3-1----32------641-98-75358-46329-248371569675298134931546827862734915154629378793815642329157486416982753587463291 +3--2-4918--2------8-71--3-22-9761534--1538-7--5---2--------5-9-9-84---255----7183365274918412389756897156342289761534641538279753942861136825497978413625524697183 +---1-62--1-3-24----6-----8--15---37-----4-1--6-87---2-8395-17-2-214879-6----3-8-5984176253153824697762359481215698374397245168648713529839561742521487936476932815 +9----4---2--9------372-8-497-865-4--4-1--925-5-3--7-68859-4--16-1-7--9------9583-986514372245973681137268549728651493461839257593427168859342716314786925672195834 +--1--9-269-2--3-47467-82--13---98-14----25----98471--36-9--4-72---9-----7---1648-531749826982163547467582931375698214146325798298471653619854372824937165753216489 +------9587---86-----81-2476-1--9---7-2--751-49----18-2-8-3--72---1-6-3-5-39---6-1162743958745986213398152476614298537823675194957431862586314729271869345439527681 +7---5832-9--2-146---63-915723-91-7------8-29----53281-----25--158--94-3----8-----741658329953271468826349157238916745615487293479532816364725981587194632192863574 +28-7----4--6------1-7428-6-8-9-3724-65-8-4-3---3-----89-127---3---9-3--1--41865-2285769314496351827137428965819537246652814739743692158961275483528943671374186592 +--5------2---159639-7--352-5-6437182--3298--7-8--5----8---7-239----8---66-9--18-5135962478248715963967843521596437182413298657782156394851674239324589716679321845 +---7-----2---6817---3-41---37-124----9-63-42-64--7----1392-6--542--179--58-4-36--918752364254368179763941258375124896891635427642879531139286745426517983587493612 +1------7--2-6-85--95-31----6-3----9-5-24963-14-812-765---9-1-272-----1-8-6--8----186549273324678519957312846613857492572496381498123765845931627239764158761285934 +7-6--5219------435-59-1-----136--7-2--7-4-5-6-4-7----1---8-49-78--5--16--9---78-3736485219128976435459213678913658742287341596645792381361824957872539164594167823 +----5-9--3-1--6--8-94---7-6----7-14--8961523-1729-468----3-98---3------19-758----726458913351796428894123756563872149489615237172934685215369874638247591947581362 +-----5---2497--3-5-759-1--21----29767635-4281----6-5--9276--1--4-----6--5-64-9--3618325497249786315375941862154832976763594281892167534927653148431278659586419723 +2-16--9--6-9---52-37---2-8---35---9-9-431--7-8-7-9---5518---------86---3436-798--241658937689731524375942681123587496954316278867294315518423769792865143436179852 +9-8-21-----567--8-1-----4--5------16---19-5-4--7--6---85-739-2136--1574872----9--948521367235674189176983452592347816683192574417856293854739621369215748721468935 +-9--------15-4-926-231--7----98-1-7-----5-1--1769----82--6-9-4----41-23543--82691894276513715348926623195784549861372382754169176923458251639847968417235437582691 +--3-89524-8--571-3-2-46-9-7-----6---64-81---9---74--5----6--7-8---9746-597-5-82--763189524489257163125463987857396412642815379391742856534621798218974635976538241 +--945--8---3----2------7---9--215-683218---598-5-932--294361---15-978-3------4--1679452183413689527582137946947215368321846759865793214294361875156978432738524691 +--3-456-9------8----5826-----46-1--55-14--3-26-9---7--94-162-3--56-7--1-1-258--96813745629267319854495826173724631985581497362639258741948162537356974218172583496 +----8--5323----87---56-----4-312--------3-7--65-8----13-8-95617----642--962-18-34796482153234951876815673492483127965129536748657849321348295617571364289962718534 +542-76--3--3--8-648-6--1-52-87523--1----69---1---87-35---8-----2---3457-4-8--5-26542976813913258764876341952687523491354169287129487635765812349291634578438795126 +---75--262-----7-9-1---9---1-3----5-4-21853-78-9-72614-2-91-4--7------6-54--37---984753126235861749617429538173694852462185397859372614328916475791548263546237981 +---418----726594--4-6----9-9-857---21--9----7--724--1-6--83-7---3--92--4---76-1-3593418276872659431416327895968571342124983567357246918641835729735192684289764153 +7-9-35264---96-587--52-4--9-4-3-6--1----8-6--1264---3-4--------68--9-42557-6--1--719835264234961587865274319948326751357189642126457938493512876681793425572648193 +1--85--6---3974-2--8-62--93--82-9----5-18--4-9-1-46--83--7--9826-9----578--4-2---192853764563974821487621593748239615256187349931546278314765982629318457875492136 +--8-7----95--2387---3--8----67-8--43-94-5-21--254-1--74827--16-6----5--8---84--92218674359956123874743598621167982543894357216325461987482739165679215438531846792 +-3-87-495-873--16---65--3-73---8-546-681-------5---2---1345---9-2--3----6-97-18-4132876495587394162946512387391287546268145973475963218713458629824639751659721834 +16-2---57-274----198457--2-841-5-2-----6---15-3------4-587-61-9--984--62----2--3-163298457527463981984571623841357296792684315635912874258736149319845762476129538 +7--6-34---1-----9-48--12---3---6-----7----1-6---1-8-79-32----8--56-71934-473852-1725693418613854792489712653391467825278539146564128379132946587856271934947385261 +94--5--611---4---857---8-4-62-4----3-15-7-2--43-82----3917--45-786-----------1-37948257361162943578573168942629415783815376294437829615391782456786534129254691837 +741--58--3-----1529-2831-6-----94-854---836--8-5----34-8-32---62--7-----197----28741265893368947152952831467673194285429583671815672934584329716236718549197456328 +8493---5----8---29231-75-4-3-54-12---6-75---3-2----51--17---4-56-21--89-4--5---6-849326751576814329231975648395481276164752983728639514917268435652143897483597162 +189-736-5--3---17-5-6-4-9--7------898--1-7-5-6-43-8----5-43-72--67--2---24-78-5--189273645423965178576841932715624389832197456694358217958436721367512894241789563 +3-4-----9--713-6--6-1-7-2-547-213-5--63--9-1-1-2-6834---6382-----------8--56-74-3354826179927135684681974235478213956563749812192568347746382591239451768815697423 +3--548--94------82-19327--5---2--9-719-6---3-5-7-392--7---624-89---5---6---7-159-326548179475196382819327645638214957192675834547839261753962418981453726264781593 +------7---8-72569---63--24--9-6-------7--13566-1-3--7--68249---21-5764-87-5-8---2532964781184725693976318245893657124427891356651432879368249517219576438745183962 +-9135----5-7----9------74--8-5643-291425-9-67-3-----48---8-523--1-----5-2--47-9--491358672527164893386927415875643129142589367639712548764895231918236754253471986 +1--64-7-24--7--5---5-13---4---352----7----3-9--3967-413---71-8-8-549------428-9--138645792496728513257139864941352678672814359583967241329571486865493127714286935 +-4-38271--2--9--6887--562-33-4--16-2--9---8-76--2-8--17-861---4--5---------835--6946382715523197468871456293384971652219563847657248931738619524165724389492835176 +6-8----147126----5---3-7--2---7-1-2---392-8--2---34-915-147-2----7163-5---428---9638592714712648935495317682849751326153926847276834591581479263927163458364285179 +5821976-37--4581-----3---8-3-8--24-66--8-----4157----81642-3--5------3---53--17-4582197643736458129941326587398512476627834951415769238164273895879645312253981764 +-63----71----51-36--1-374----89-----592----833--78---4--7---268-85372-4-129--63--263498571974251836851637492748923615592164783316785924437519268685372149129846357 +9-4--78--3-7-2-514--5----------72439-2946-175-4-5-1--25--7-6--8----3-7--178--5-6-914357826387629514265184397651872439829463175743591682532716948496238751178945263 +7--2---3--3-54---729-83--5---1-25-4----36-71-6--91-3--46------2---479----536824--745291836138546297296837154381725649529364718674918325467153982812479563953682471 +6--92-431--917-6-8--35-47-2-548-92-----4-7-1-----5-----27-91--3-----59-7---7421-5675928431249173658183564792354819276862437519791256384527691843416385927938742165 +-19-----23-8294-1----615-------3975--9--67-3-7--8-21---5--2-3---26-438----3-81--5519378462368294517247615983682139754195467238734852196851726349926543871473981625 +532-4--964-9--7--217--69--4----76--18----2---2574---6---3-14-25----8--4-6-57-31-9532148796469357812178269534394876251816592473257431968783914625921685347645723189 +-2--9-6--9----28-136--8-4-9--5-1--86-7-9--3-5---25-9-7------13271---6---8-91--764128497653954632871367581429495713286271968345683254917546879132712346598839125764 +7-18-3---95-6---8------12------793--1-6-54928493-68-71--59-----31----6-2-----6-15761823459952647183834591267528179346176354928493268571685912734317485692249736815 +----6---36-1--345--378-16-27---1-86-186--49-7--------496458---12-3-9----87--3-2-9428965713691723458537841692742319865186254937359678124964582371213497586875136249 +-8----1--3-5-47------3-8--4----5--61-43712-891596-3-42-36---2-5----7---38-12--4--284569137365147928917328654728954361643712589159683742436891275592476813871235496 +-6--43--2------716-295-7---------84----2-46-147-681-2324--1-3--38----2599---281-4768143592534892716129567438612739845893254671475681923246915387381476259957328164 +2-6---5-3-------275739-286--5-2-6--8---7-814676---12-582-3--6--------3599-461----246187593189563427573942861451236978392758146768491235825379614617824359934615782 +75-8123-9-29374---8-19----7------8----2-6-73--9-78124-2-56---8--4--2------8--5612754812369629374158831956427167243895482569731593781246215637984946128573378495612 +7-38---256-94--1-32-8-539----49-------1-4----87-21--49432--9-56---3-42-7-6--8-4--743891625659427183218653974524936718391748562876215349432179856185364297967582431 +4----9687-6--2------76-4-9---19-85--253-61---68954-1-3--------9895-1--26-7---6-35412359687968127354537684291741938562253761948689542173326875419895413726174296835 +784----------812--5123-9--889---37--35--24-9--2--7--3-2-96---8-64--1---313-----67784256319963781254512349678891563742357124896426978135279635481645817923138492567 +---61---856-39-7-------5----2-56-17--9-8-143---49-7682----5-91----17685-71--89-2-473612598562398741981745263328564179697821435154937682846253917239176854715489326 +8-3--416---2-----------6532--93-8---5-46-7--16----1-73-7--639--38-7-52-6-4-81-357853274169162539784497186532719348625534627891628951473275463918381795246946812357 +15-4-7-2-739--54--28---1--69-5-----2---3-87-13--572--45-7---2--62---9-8--912--6-7156487329739625418284931576975164832462398751318572964547816293623749185891253647 +1-967528----9-2-65------9-7--472--967-8---3429-2-6---824-1-3---------6515--89--2-139675284487932165625481937314728596768519342952364718246153879893247651571896423 +43-21-6-5-8--542--2516-97--9--42--715-2-9---4---56--8--94-7--56-------3-315-4----437218695689754213251639748968423571572891364143567982894372156726185439315946827 +7---14-583---8---6---3-672-6-7--5-39----735--23-9--8--4--15----9---3-614-23-6-975769214358312587496584396721647825139891673542235941867476159283958732614123468975 +81247--5--4---8--9---3-218---8---5----6-----893-58-2-64-51-68--3-172-9--2-9--5-17812479653543618729697352184728963541156247398934581276475196832381724965269835417 +6------7----3-21-4--271-----2915-648-78936-21-56--4---9-4----152---9-7-6--1--3---613845972897362154542719863329157648478936521156284397934678215285491736761523489 +--53--12--2---9-84---6-235-1-8--473-3---6-49---6--38--5-9-8----43-9--578------961695348127723519684814672359158294736372861495946753812569187243431926578287435961 +316-47--2-----1----9--83-7-834----272--3--16-1672-83-5-7------4--5769-1-9---1-75-316947582748521639592683471834156927259374168167298345671835294425769813983412756 +7------3--3-8-72-4-8613-79--2-76851-8----16-7-------2-6-4275-8-3---1695-5--3-9---745692138931857264286134795429768513853921647167543829694275381378416952512389476 +47219------18--69--9----4-----31--25-5---8-1631-56----745--1--392--8-167-6-937---472196538531874692896253471684319725259748316317562849745621983923485167168937254 +8-36---29-965----845129--6----3---82--7-----5185-2-6---4-15--36----6--7--129-38-4873641529296537418451298367964315782327486195185729643748152936539864271612973854 +6--284-1-58-----4-2--1756-97-65------1-3---96--5-6172--6279----3----2-6-8-4-53-7-679284315581936247243175689726549831418327596935861724162798453357412968894653172 +6-5-41--2---385--1--3------56-13-9-8-9--7--15-2-95864-8-24--1-91--5-9--4--7---5-6685741392279385461413296857564132978398674215721958643852467139136529784947813526 +6---215---3-----7----7-468--53-78---7-2----5----2--1--4-7819-653165-7-92-8-----14678321549534986271291754683153478926762193458849265137427819365316547892985632714 +3------61-9-8-1-2-57---2-894-----------174-9-16-92--5--16-49-78--8-3-91---57182-6382497561694851723571362489429685137853174692167923854216549378748236915935718246 +5-932-8---1274-6---4-58--92----6-4------1--6-6-48-351--6---7-8--53---2-69-7652--4579326841812749653346581792138965427795214368624873519261437985453198276987652134 +--2-5------32-----17-38--25248--5-69-9-1--2------428-77-4-1--869-5-2-3-48-16-45--682459731453271698179386425248735169597168243316942857724513986965827314831694572 +3---154---1-86--9-----3421-6-5-47-8-2----6-4---4-98--29-3-----6-486739-----529---392715468417862395856934217635247189289156743174398652923481576548673921761529834 +3------5----46-9-1-6-5-9----9--4----6----85-381-----97-25834-69-869-7312-37-1----349271856258463971761589234593746128672198543814325697125834769486957312937612485 +8-63172---27-----1---952----158-3-6---82-6--9-9---1-8-4--16--2--7-4-58-----7-894-856317294927684531134952678715893462348276159692541387483169725279435816561728943 +-51-3-7-279---2-8----17--3--4-3-6---9-75--123-2-7--654-1-64-3-8-7-8----5----5791-451938762793462581286175439145326897967584123328791654512649378679813245834257916 +--34--1---1-59---3-2471-5---69-----415-674-9----932---8---459----628--1----16-83-593428176718596243624713589369851724152674398487932651871345962936287415245169837 +-7384---2-8--5----4-92-61-3---7--5----416-----1---8736--891-46---76--8-9-91-8-327173849652286351974459276183862793541734165298915428736328917465547632819691584327 +46-72-1--78-1--42---25-4--------894--7--153---486935-1----4--638-6-57---9-4-6--1-463729158785136429192584637351278946679415382248693571527941863816357294934862715 +-4-6-------374-5--612---34--8--37--5----2893-93----87-168--9--342-371-5--7----491547613289893742516612895347284937165756128934931564872168459723429371658375286491 +7-643------98-26--3------5-84-----7-12-39-58669-1784-3---7-3-95--8-2----9-----3-2756439218419852637382617954843265179127394586695178423261743895538926741974581362 +7-6--8----8957-3----319-7-8-7-----4596--15----5--27--34257-163-1-----2-763-9--4--716238594289574316543196728372869145964315872851427963425781639198643257637952481 +-1--684--5247-1---76834-12--9--73--6--75-----3----6798-------6---9--7-428461---75913268457524791683768345129492873516687519234351426798275984361139657842846132975 +7-------5-91-857--4-572-86-1---------56--2--82-36581--3-42-6--78--513-96----74--3782461935691385724435729861148937652956142378273658149314296587827513496569874213 +2-5--7-----931-7-2-7142---959-1----83-----2-68642-3-9515--34----4--629---2----48-235697814489315762671428539592146378317589246864273195158934627743862951926751483 +----1-5-44815---27596------75--9---21----29--82---71-6-17--5-3-24-9-3---63-2--4--372618594481539627596724813754196382163842975829357146917465238245983761638271459 +867---------2--61-912--6-5414--38---2-5-6---337---41---2--4-8--65-8---4-49--5-27-867415932534297618912386754146938527285761493379524186723149865651872349498653271 +-6-3---9-9--51---623-49--5---7-35-1--8-27-9-----98-67-5-98431-----162---81------3165327498974518326238496751497635812681274935352981674529843167743162589816759243 +----625-7--81----6672-4-83-1-59-746--6---4----9-6-----71-32---452---137-84---62-9931862547458173926672549831185937462367284195294615783719328654526491378843756219 +---7----592---86--1-5---8-3---3---195-6987-24493-51-6835-67------2---9------25--6834716295927538641165492873278364519516987324493251768351679482682143957749825136 +1---62-5-7------8----4-------169853-987--516-6-571---8218937----69541-7----2--9--143862759792153486856479321421698537987325164635714298218937645369541872574286913 +17-----824-6--73-5--2--86---6-8-1-9-8-9-72--4-4----7-879418-2-------543-325--98--173654982486297315952318647267841593839572164541936728794183256618725439325469871 +-----5--65-86--19--6482-5-3--------14----825-8251--7-4751-92--83-6--7---24---63-7132975486578643192964821573697254831413768259825139764751392648386417925249586317 +61-28-75------56---85-6--43--1--8-25------4--258-4-19-5493-28--1-2--697--67--9---613284759724935618985167243471698325396521487258743196549372861132856974867419532 +--9--38-4-3--9---5-57-4-9-16---8-54--2-9--6-7---36-2-99-48--152------378-82--5---169573824438192765257648931691287543823954617745361289974836152516429378382715496 +-235-4-----56-24---7--98-2---7481-59---763---8-----7-4-5-8--3--3--9-7--5-9-1-58-6123574968985612473674398521237481659549763182816259734451826397368947215792135846 +32----8---8-3-5-24--4-216--5--21-4388-7--9---2----457979---3-866----2--5-52---31-325746891186395724974821653569217438847539162213684579791453286638172945452968317 +-163-52------8----4-2--15-82-1--98-45-4--8--33--6-41521-38-69-----4-7---9--213-86816345279735982641492761538271539864564128793389674152143856927628497315957213486 +2-9--17-3---3--2--3--5--986--89635---3-7-----7-28456319-5--8-67--7------6--1-7829259681743864379215371524986418963572536712498792845631925438167187296354643157829 +6---781-93----48-----65--344-6-32--753-8---2----7--6-32--4193--9-----71--532674--642378159315924876789651234496132587537846921821795643278419365964583712153267498 +--15--43-24836-1--5-39--82----73-----561829--9--65-21-8--41--62-----5---4-52--38-791528436248367195563941827124739658356182974987654213879413562632895741415276389 +9----63-882-4356--7--9-85-429-7--4-618-------654-927--36-5---42--9------4--3-98-5945176328821435697736928514293751486187643259654892731368517942579284163412369875 +2357-4--8------4---84--26-58172963-46--5812-----4---1-4-1--75-33--1-----5286----1235764198169358427784912635817296354643581279952473816491827563376145982528639741 +5----9762--7-8-----6-7-5--979235-14--1-9-23--843-71---239-1--78-------9---6--7-34581439762927186453364725819792358146615942387843671925239514678478263591156897234 +----138--12-8-7-----3----5--41---26-35--6--8----7--1--592-416-8---2--5-4-185769-3975613842124857396683429751841935267357162489269784135592341678736298514418576923 +47-3---1-6-------7---17-628--9--1856148-3-7-2---798--4-14--3--5-2591-------54-9-1472386519681259347593174628739421856148635792256798134914863275825917463367542981 +--5---7--23-7-6-5-7-9-51-68--2------87-1--6--4-1687-2-9-481-5-----9-54----64728-3165298734238746951749351268692534187873129645451687329924813576387965412516472893 +-1-76-3--9--4528----738-4-914--23--7--617-2--7--8-4---43----6-5-9-5--748-7-2-8---814769352963452871527381469149623587386175294752894136438917625291536748675248913 +-8----2--3-4-51------48---1-----5--42-87--1--94----7-341-572-8663294--17-----3-92187369245394251678526487931763195824258734169941826753419572386632948517875613492 +5--3--46--1--7-------59-8-78-7-53249145-267-3-9--48------4----6-31---97-7-6-3----579382461318674592624591837867153249145926783293748615982417356431265978756839124 +75-21936-86935-41---2---79-54-----3--83-25------4----9--8----5-6---94--3---57--26754219368869357412132648795546981237983725641217436589378162954625894173491573826 +39---74---14--936-758-36-9-475-6---9-----164--2----7--56-1-38-48---7591-----9--2-396217458214589367758436291475362189983751642621948735569123874842675913137894526 +-6-2--49-8---7-2-352----7-8-8--5---4-9--438-1--5--86-9--4-67---6--8-9147------536763281495849675213521394768187956324296743851435128679314567982652839147978412536 +23--8-4-5------2--56872---37138496-2--45138-----2---1-1-2-7-5-6--61-----3854----1237981465941635287568724193713849652624513879859267314192378546476152938385496721 +--6239-145-3---7----45769---3-49-6-29----814--42--3---46-1-2-----8-6-4---7538-2--786239514593841726214576938831495672957628143642713895469152387328967451175384269 +8932-51--641----------13--97-4-3-2--95-7---1-3-2---67-1-5--2--62-8-94-5---9-6--2-893245167641987532527613489784136295956728314312459678135872946268394751479561823 +7---9------6--83-14-8----7586-7-514223-819-6715--4----6--3-7------96-7-4--1----3-713596428526478391498123675869735142234819567157642983645387219382961754971254836 +-----3-9-78---5-6---2------348-51--65---68349-693---85914---673--7-4----625--98-4156823497783495261492617538348951726571268349269374185914582673837146952625739814 +52316---7847---------3-72--3-6----9821--9--7-9-4--3--67-16--8--6-54-2-1---2--8-6-523164987847925631169387254376241598218596473954873126731659842685432719492718365 +-64-58--1--1-43-65---6--4-723-----4--1-49--3----38-57---2--571--49---8--1-78-4293964758321871243965523619487238576149715492638496381572682935714349127856157864293 +-5-3-4217--48-1-65--2-79-38---9-----9-7-46--3----871-----738-91----9--843-841--2-859364217734821965612579438481953672927146853563287149246738591175692384398415726 +--5-9----6--2---182-3---54--624-5371-41-3-----8791265---65-8-------69-351-----8--815694723674253918293871546962485371541736289387912654436528197728169435159347862 +-7--6----63-49--8-8-52-3-4121-6--5-35--9---26-6-12-89415-3-------6-1-4599-------7471568932632491785895273641219684573548937126763125894157349268386712459924856317 +-1-8-----987---136325-9--4864827---3-93--64-22--34-869-5-----------6-9--1-4-2-3--416837295987452136325691748648279513593186472271345869859713624732564981164928357 +1--98-3--932-674--58-2-379-2598-------------56-84---79---7-9--1-936---8--6-3-8-24176984352932567418584213796259876143347192865618435279825749631493621587761358924 +-73--48-5--2--63--41-----62-69-42--73--6-1-9-7-----4-694716-2-------578-285--96--673294815592816374418357962869542137324671598751983426947168253136425789285739641 +-584----9-49----5326--5--1---63---9--12--93---976-8-2-674-92--1---1-46--831------758413269149286753263957814586321497412579386397648125674892531925134678831765942 +---4-56-119----5-465---1-8------64727652-98--4--713-5----3972-5-26-5---8--3--2---238475691197638524654921387319586472765249813482713956841397265926154738573862149 +8-62--4717-5--8-3291---4-65--9------38--91--615----7--561----97-9-----58-78-65-4-836259471745618932912734865629587314387491526154326789561843297493172658278965143 +4-------6-1-25--9-79--84----5---2------47-6-11-----24-9-153748-5-8-----73-2-41965425793816813256794796184523654912378239478651187365249961537482548629137372841965 +9--4--6314-6-1--9--7---6---3-9-5-2--56-782----426935-86----1-82-5-329-76--------9928475631436218795175936824389154267561782943742693518697541382854329176213867459 +-84-9-5-73-765-19-9----7----76--5--11-2-4-7654-------------29-32-3--9-165--8-6472684193527327654198951287634876925341192348765435761289768412953243579816519836472 +52-6-1---------9363--74--5-4-5-9---78-7---125--285--49------4-86-498357----4-5-93529631784741528936386749251435192867897364125162857349953276418614983572278415693 +-8--64-9596--57--8-259-----5-----37-7--51--8-2-674----8-2--6--3--4----511734-58-2387264195961357428425981637518629374749513286236748519852176943694832751173495862 +5-2--36-7---6----2--61--4952-79813649--546--1-6-7-----1-5--974-7----------43-7529512493687849675132376128495257981364938546271461732958125869743793254816684317529 +--256----15--72--497--4--25-----531--85--1-4--917-6---5-93184-6---9---587--6-4--3842569731153872964976143825267485319385291647491736582529318476634927158718654293 +1365----8---1---37725-48--6--7---8-2--948--5-58-6-27---42---68-6--8----997-2--1-3136579428894126537725348916417953862269487351583612794342791685651834279978265143 +-98-----5---397---1-42859-----81-36-6--5-4-9--8-67-1----194---3-5712--4--3--5--1-398461725526397481174285936745819362612534897983672154261948573857123649439756218 +-1---42786--1583-9489---5--5-7---1-4-6--157--1-4-37-----659--1----2--9--9-1---832315964278672158349489372561537629184268415793194837625826593417743281956951746832 +476-58-3--1-7-9-4-92-64-75-8--49-6-37-48--9-----57---1-893--5-7--------22679-----476258139518739246923641758851492673734816925692573481189324567345167892267985314 +4-8--61-5---5--8----53--429--96-12841--------3-4--2-91-5-1-----2--4953--8-1273956438926175792514863615387429579631284126849537384752691953168742267495318841273956 +-9-185-732--79---173--42--9--9218-3-32------41---6-----6-----9-94-5---185-283-4-7694185273285793641731642859459218736326957184178364925863471592947526318512839467 +--34-8---9--13-6---81-62--3-1-39-2----58764--3--24-8-5-28---9-7-5-7--384-3-6-4---673458129942137658581962743814395276295876431367241895428513967156729384739684512 +------7---5---6----1---2-8419-2--835--51-862-28-653--1-6-38-172---5243963-----4--942815763758436219613972584196247835435198627287653941564389172871524396329761458 +--129-6---8------7-564-8---93-8-176216-32548-42------5-1----89----58--71--2--9---341297658289653147756418923935841762167325489428976315514732896693584271872169534 +-----16--9--5--21-51-863-----9--4-5242--75---75-----84--5436--7-9--18523173--2---847291635936547218512863479369184752428375961751629384285436197694718523173952846 +-98-5-7-6---8------7--9215--3--182-5----46---8-1527--3-86-3-5-7--2-8-6-9957-61--2298154736615873924473692158734918265529346871861527493186239547342785619957461382 +1---7629-79--251--8-29------8756-----5-23--1--2-----54-18--74----6---32-5346-28-1145876293793425186862913547487561932659234718321789654218357469976148325534692871 +9-72--54--386--17-4---8736--2439-6-1---4---2-----2--9--85--42372---6---53-17-2---967231548538649172412587369724398651196475823853126794685914237279863415341752986 +92-1-6-47----3-8---4--5213-8------5-572-9---3-----179-254-693--36---5-7-1-7--396-923186547615437829748952136891374652572698413436521798254769381369815274187243965 +42-3--1788--------79--4---6---2----4614-8-5---8--54-6---7-18-3----43-2979-35-7481426395178835671942791842356579263814614789523382154769247918635158436297963527481 +----638-5-------6976-98523-5--62-3--------5873-1-74---63-8----292----143-1-39-6-8192463875853217469764985231579628314246139587381574926635841792928756143417392658 +297-5-6-----93-2--346-7--1583--924--7---8-5---145-7-----3-45-----86--15-65---37-4297451638581936247346278915835192476762384591914567382123745869478629153659813724 +39---5-8-51-2--7434-----------1---5--4--56--8875--46----3-47--29-263-574---5-2139397415286518269743426873915639128457241756398875394621153947862982631574764582139 +5-8--4-31---5-------3-7849---6-59-74----12---95-437--61-5--6-437----5-18384-91--7578924631419563782623178495236859174847612359951437826195786243762345918384291567 +-----7-14749-1-3-2618-------932---76-7-3---8--21--8--3-3458----2-71--5---65-3--4-352967814749815362618423795893251476576394281421678953134589627287146539965732148 +-3-17--45-9--46-287-4--2-319------6-61-92-5-3-2-----9---278-4193----98---49-51---236178945195346728784592631953817264617924583428635197562783419371469852849251376 +2--1659--81----5--6--798-42--82-96-7-9--3-42-7-2-8-----2647----3----62--1-58-37--274165983819342576653798142438219657591637428762584391926471835387956214145823769 +82-4-3-69-516--2-46---2----5---------32-4-9--97-5--432----7-8-64---3172578--6-39-827453169351689274694127583548392617132746958976518432213975846469831725785264391 +-93--6---1-89--367------9425---9--86-3-1--4-5---25-1-3-64-8-7-1--1--28-9-2--1-6--293476518148925367675831942517394286932168475486257193364589721751642839829713654 +--5---49----432---4--915-78-8-5--3---7-18-52---374--8-36-89-----4--57--68--26-9--215678493798432165436915278189526347674183529523749681361894752942357816857261934 +87--13--2--972--1--2-6-8-----236--84-4-851-6-7--29--3-4--5--82638-----952--1-6---874913652639725418521648379152367984943851267768294531417539826386472195295186743 +-968-7---4--9-3--7-37----69-19---852--413-9------5---1261-----3-4-392-189----6725196827534452963187837541269319674852524138976678259341261785493745392618983416725 +1247965-3968--1--4--5----9---16489----9--3---7--9-53-84--56-8-1--------55-78346--124796583968351274375482196231648957859173462746925318492567831683219745517834629 +3-67----4--438-5695-92--7-34-587-2-----13------2495-7885-64-9-------7---9-35--6-7386759124274381569519264783435876291798132456162495378857643912641927835923518647 +------593-7-25------54-8271-3-8--4-54--97-1-88---3-7--6-3---8-2--8-2-9-65----6-47284617593179253684365498271937861425456972138821534769613749852748325916592186347 +--7--4---394---587816-3-42-542-968--6---28354-835--6-272--6---8--1----------5---3257984136394612587816735429542396871679128354183547692725463918431879265968251743 +---3---4-7-6-28----83---7-----81-25--5--43-7-6-----8---182945-746578-9-32-----4-1129375648746128395583469712934817256852643179671952834318294567465781923297536481 +6--4-2-97-549--632-297634----3-----8---698753-7-32-914-4---982--6---7-----------1638452197754981632129763485593174268412698753876325914347519826261837549985246371 +---5-41--6--1739-81-592-4--3--------2-1697-3--792--6--4-----7---837-6-4-5-7-42-69798564123624173958135928476356481297241697835879235614462359781983716542517842369 diff --git a/apps/trail/ChangeLog b/apps/trail/ChangeLog index 097869de3..ae1c44012 100644 --- a/apps/trail/ChangeLog +++ b/apps/trail/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.10: Redesign to make screen updates fast +0.11: bugfix (demo mode was enabled by default) diff --git a/apps/trail/metadata.json b/apps/trail/metadata.json index 3cb9672c7..0981d6dbe 100644 --- a/apps/trail/metadata.json +++ b/apps/trail/metadata.json @@ -1,6 +1,6 @@ { "id": "trail", "name": "Trail Rail", - "version":"0.10", + "version":"0.11", "description": "Follow a GPX track in car or on bike", "icon": "app.png", "readme": "README.md", diff --git a/apps/trail/trail.app.js b/apps/trail/trail.app.js index aa06d9e1d..601a9f089 100644 --- a/apps/trail/trail.app.js +++ b/apps/trail/trail.app.js @@ -134,7 +134,6 @@ let gps = { init: function(x) { this.emulator = (process.env.BOARD=="EMSCRIPTEN" || process.env.BOARD=="EMSCRIPTEN2")?1:0; - this.emulator = 1; // FIXME }, state: {}, on_gps: function(f) { @@ -602,7 +601,7 @@ function step_to(pp, pass_all) { return quiet; } -var demo_mode = 0; //fixme +var demo_mode = 0; function step() { const fast = 0; @@ -666,7 +665,7 @@ function step() { drop_last(); let v2 = getTime(); print("Step took", (v2-v1), "seconds"); - setTimeout(step, 10); /* FIXME! */ + setTimeout(step, 1000); } function recover() { diff --git a/apps/widbatpc/ChangeLog b/apps/widbatpc/ChangeLog index e9326fd2c..34873124c 100644 --- a/apps/widbatpc/ChangeLog +++ b/apps/widbatpc/ChangeLog @@ -17,3 +17,4 @@ Add option to disable vibration when charger connects 0.18: Only redraw when values change 0.19: Match draw() API e.g. to allow wid_edit to alter this widget +0.20: Remove clear of the screen on reload (will break currently running app) \ No newline at end of file diff --git a/apps/widbatpc/metadata.json b/apps/widbatpc/metadata.json index 4c364a864..5e160b5d4 100644 --- a/apps/widbatpc/metadata.json +++ b/apps/widbatpc/metadata.json @@ -2,7 +2,7 @@ "id": "widbatpc", "name": "Battery Level Widget (with percentage)", "shortName": "Battery Widget", - "version": "0.19", + "version": "0.20", "description": "Show the current battery level and charging status in the top right of the clock, with charge percentage", "icon": "widget.png", "type": "widget", diff --git a/apps/widbatpc/widget.js b/apps/widbatpc/widget.js index 7ba060d6d..163c0f541 100644 --- a/apps/widbatpc/widget.js +++ b/apps/widbatpc/widget.js @@ -156,7 +156,6 @@ // need to redraw all widgets, because changing the "charger" setting // can affect the width and mess with the whole widget layout setWidth(); - g.clear(); Bangle.drawWidgets(); } diff --git a/apps/widbt_notify/ChangeLog b/apps/widbt_notify/ChangeLog index d48cdca63..74f8515db 100644 --- a/apps/widbt_notify/ChangeLog +++ b/apps/widbt_notify/ChangeLog @@ -13,4 +13,5 @@ 0.14: Added configuration option 0.15: Added option to hide widget when connected 0.16: Simplify code, add option to disable displaying a message -0.17: Minor display fix \ No newline at end of file +0.17: Minor display fix +0.18: Use notify lib to stop this widget clearing the screen of the running clock/app \ No newline at end of file diff --git a/apps/widbt_notify/metadata.json b/apps/widbt_notify/metadata.json index 5e3f15af2..4eda86941 100644 --- a/apps/widbt_notify/metadata.json +++ b/apps/widbt_notify/metadata.json @@ -1,13 +1,14 @@ { "id": "widbt_notify", "name": "Bluetooth Widget with Notification", - "version": "0.17", + "version": "0.18", "description": "Show the current Bluetooth connection status with some optional features: show message, buzz on connect/loss, hide always/if connected.", "icon": "widget.png", "type": "widget", "tags": "widget,bluetooth", "provides_widgets" : ["bluetooth"], "supports": ["BANGLEJS","BANGLEJS2"], + "dependencies" : { "notify":"module" }, "storage": [ {"name":"widbt_notify.wid.js","url":"widget.js"}, {"name":"widbt_notify.settings.js","url":"settings.js"} diff --git a/apps/widbt_notify/widget.js b/apps/widbt_notify/widget.js index 4730db5b5..bde218236 100644 --- a/apps/widbt_notify/widget.js +++ b/apps/widbt_notify/widget.js @@ -1,6 +1,6 @@ -(function() { +{ // load settings - var settings = Object.assign({ + let settings = Object.assign({ showWidget: true, buzzOnConnect: true, buzzOnLoss: true, @@ -10,7 +10,7 @@ }, require("Storage").readJSON("widbt_notify.json", true) || {}); // setup widget with to hide if connected and option set - var widWidth = settings.hideConnected && NRF.getSecurityStatus().connected ? 0 : 15; + let widWidth = settings.hideConnected && NRF.getSecurityStatus().connected ? 0 : 15; // write widget with loaded settings WIDGETS.bluetooth_notify = Object.assign(settings, { @@ -31,24 +31,13 @@ g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="), 2 + this.x, 2 + this.y); } } else { - // g.setColor(g.theme.dark ? "#666" : "#999"); + // g.setColor(g.theme.dark ? "#666" : "#999"); g.setColor("#f00"); // red is easier to distinguish from blue g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="), 2 + this.x, 2 + this.y); } } }, - redrawCurrentApp: function() { - if (typeof(draw) == 'function') { - g.reset().clear(); - draw(); - Bangle.loadWidgets(); - Bangle.drawWidgets(); - } else { - load(); // fallback. This might reset some variables - } - }, - onNRF: function(connect) { // setup widget with and reload widgets to show/hide if hideConnected is enabled if (this.hideConnected) { @@ -61,10 +50,10 @@ if (this.warningEnabled) { if (this.showMessage) { - E.showMessage( /*LANG*/ 'Connection\n' + (connect ? /*LANG*/ 'restored.' : /*LANG*/ 'lost.'), 'Bluetooth'); + require("notify").show({id:"widbtnotify", title:"Bluetooth", body:/*LANG*/ 'Connection\n' + (connect ? /*LANG*/ 'restored.' : /*LANG*/ 'lost.')}); setTimeout(() => { - WIDGETS.bluetooth_notify.redrawCurrentApp(); - }, 3000); // clear message - this will reload the widget, resetting 'warningEnabled'. + require("notify").hide({id:"widbtnotify"}); + }, 3000); } this.warningEnabled = 0; @@ -87,4 +76,4 @@ NRF.on('connect', (addr) => WIDGETS.bluetooth_notify.onNRF(addr)); NRF.on('disconnect', () => WIDGETS.bluetooth_notify.onNRF()); -})() \ No newline at end of file +} \ No newline at end of file diff --git a/apps/widmessages/ChangeLog b/apps/widmessages/ChangeLog index 314b1490c..35bde7bbd 100644 --- a/apps/widmessages/ChangeLog +++ b/apps/widmessages/ChangeLog @@ -4,4 +4,5 @@ 0.03: Fix messages not showing if UI auto-open is disabled 0.04: Now shows message icons again (#2416) 0.05: Match draw() API e.g. to allow wid_edit to alter this widget -0.06: Fix bug that meant that only one widget was shown (now 3 unless changed in Settings->Apps->Messages->Widget messages) \ No newline at end of file +0.06: Fix bug that meant that only one widget was shown (now 3 unless changed in Settings->Apps->Messages->Widget messages) +0.07: Only load messages module if we have messages (30ms speed improvement) \ No newline at end of file diff --git a/apps/widmessages/metadata.json b/apps/widmessages/metadata.json index 436b77d3e..95a34e892 100644 --- a/apps/widmessages/metadata.json +++ b/apps/widmessages/metadata.json @@ -1,7 +1,7 @@ { "id": "widmessages", "name": "Message Widget", - "version": "0.06", + "version": "0.07", "description": "Widget showing new messages", "icon": "app.png", "type": "widget", diff --git a/apps/widmessages/widget.js b/apps/widmessages/widget.js index 0351fbead..3212ee649 100644 --- a/apps/widmessages/widget.js +++ b/apps/widmessages/widget.js @@ -65,7 +65,7 @@ if ((require("Storage").readJSON("messages.settings.json", true) || {}).maxMessa this.onMsg("show", {}); // reload messages+redraw } }; - Bangle.on("message", WIDGETS["messages"].onMsg.bind(WIDGETS["messages"])); - WIDGETS["messages"].onMsg("init", {}); // abuse type="init" to prevent Bangle.drawWidgets(); + if (require("Storage").read("messages.json")!==undefined) // only call init if we've got messages - otherwise we can avoid loading messages lib (saves 30ms) + WIDGETS["messages"].onMsg("init", {}); // abuse type="init" to prevent Bangle.drawWidgets(); } \ No newline at end of file diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index 82856b639..61a251bb5 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -5,6 +5,12 @@ var fs = require("fs"); var vm = require("vm"); var heatshrink = require("../webtools/heatshrink"); +/*var apploader = require("../core/lib/apploader.js"); +apploader.init({ + DEVICEID : "BANGLEJS2" +});*/ + + var acorn; try { acorn = require("acorn"); @@ -48,54 +54,56 @@ function WARN(msg, opt) { } /* These are errors that we temporarily allow */ var KNOWN_ERRORS = [ - "In locale en_CA, long date output must be shorter than 15 characters", - "In locale fr_FR, long date output must be shorter than 15 characters", - "In locale en_SE, long date output must be shorter than 15 characters", - "In locale en_NZ, long date output must be shorter than 15 characters", - "In locale en_AU, long date output must be shorter than 15 characters", - "In locale de_AT, long date output must be shorter than 15 characters", - "In locale en_IL, long date output must be shorter than 15 characters", - "In locale es_ES, long date output must be shorter than 15 characters", - "In locale fr_BE, long date output must be shorter than 15 characters", - "In locale fi_FI, long date output must be shorter than 15 characters", - "In locale de_CH, long date output must be shorter than 15 characters", - "In locale fr_CH, long date output must be shorter than 15 characters", - "In locale wae_CH, long date output must be shorter than 15 characters", - "In locale tr_TR, long date output must be shorter than 15 characters", - "In locale hu_HU, long date output must be shorter than 15 characters", - "In locale oc_FR, long date output must be shorter than 15 characters", - "In locale ca_ES, long date output must be shorter than 15 characters", - "In locale fr_BE, short month must be shorter than 5 characters", - "In locale fi_FI, short month must be shorter than 5 characters", - "In locale fr_CH, short month must be shorter than 5 characters", - "In locale oc_FR, short month must be shorter than 5 characters", - "In locale hr_HR, short month must be shorter than 5 characters", - "In locale ca_ES, short month must be shorter than 5 characters", - "In locale de_DE, meridian must be longer than 0 characters", - "In locale en_JP, meridian must be longer than 0 characters", - "In locale nl_NL, meridian must be longer than 0 characters", - "In locale fr_FR, meridian must be longer than 0 characters", - "In locale se_SE, meridian must be longer than 0 characters", - "In locale en_SE, meridian must be longer than 0 characters", - "In locale da_DK, meridian must be longer than 0 characters", - "In locale en_DK, meridian must be longer than 0 characters", - "In locale de_AT, meridian must be longer than 0 characters", - "In locale es_ES, meridian must be longer than 0 characters", - "In locale fr_BE, meridian must be longer than 0 characters", - "In locale it_CH, meridian must be longer than 0 characters", - "In locale it_IT, meridian must be longer than 0 characters", - "In locale wae_CH, meridian must be longer than 0 characters", - "In locale oc_FR, meridian must be longer than 0 characters", - "In locale pl_PL, meridian must be longer than 0 characters", - "In locale lv_LV, meridian must be longer than 0 characters", - "In locale nn_NO, meridian must be longer than 0 characters", - "In locale nb_NO, meridian must be longer than 0 characters", - "In locale ca_ES, meridian must be longer than 0 characters", - "In locale de_CH, meridian must be shorter than 4 characters", - "In locale hr_HR, meridian must be shorter than 4 characters", - "In locale sl_SI, meridian must be shorter than 4 characters", + "In locale en_CA, long date output must be shorter than 15 characters (Wednesday, September 10, 2024 -> 29)", + "In locale fr_FR, long date output must be shorter than 15 characters (10 septembre 2024 -> 17)", "In locale fr_FR, short month must be shorter than 5 characters", "In locale sv_SE, speed must be shorter than 5 characters", + "In locale en_SE, long date output must be shorter than 15 characters (September 10 2024 -> 17)", + "In locale en_NZ, long date output must be shorter than 15 characters (Wednesday, September 10, 2024 -> 29)", + "In locale en_AU, long date output must be shorter than 15 characters (Wednesday, September 10, 2024 -> 29)", + "In locale de_AT, long date output must be shorter than 15 characters (Donnerstag, 10. September 2024 -> 30)", + "In locale en_IL, long date output must be shorter than 15 characters (Wednesday, September 10, 2024 -> 29)", + "In locale es_ES, long date output must be shorter than 15 characters (miércoles, 10 de septiembre de 2024 -> 35)", + "In locale fr_BE, long date output must be shorter than 15 characters (dimanche septembre 10 2024 -> 26)", + "In locale fr_BE, short month must be shorter than 5 characters", + "In locale fr_BE, short month must be shorter than 5 characters", + "In locale fr_BE, short month must be shorter than 5 characters", + "In locale fr_BE, short month must be shorter than 5 characters", + "In locale fr_BE, short month must be shorter than 5 characters", + "In locale fi_FI, long date output must be shorter than 15 characters (keskiviikkona 10. maaliskuuta 2024 -> 34)", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale fi_FI, short month must be shorter than 5 characters", + "In locale de_CH, meridian must be shorter than 4 characters", + "In locale de_CH, meridian must be shorter than 4 characters", + "In locale de_CH, long date output must be shorter than 15 characters (Donnerstag, 10. September 2024 -> 30)", + "In locale fr_CH, long date output must be shorter than 15 characters (dimanche 10 septembre 2024 -> 26)", + "In locale fr_CH, short month must be shorter than 5 characters", + "In locale fr_CH, short month must be shorter than 5 characters", + "In locale fr_CH, short month must be shorter than 5 characters", + "In locale fr_CH, short month must be shorter than 5 characters", + "In locale fr_CH, short month must be shorter than 5 characters", + "In locale wae_CH, long date output must be shorter than 15 characters (Sunntag, 10. Herbštmánet 2024 -> 29)", + "In locale tr_TR, long date output must be shorter than 15 characters (10 Haziran 2024 Pazartesi -> 25)", + "In locale hu_HU, long date output must be shorter than 15 characters (2024 Szep 10, Csütörtök -> 23)", + "In locale oc_FR, long date output must be shorter than 15 characters (divendres 10 setembre de 2024 -> 29)", + "In locale oc_FR, short month must be shorter than 5 characters", + "In locale oc_FR, short month must be shorter than 5 characters", + "In locale hr_HR, meridian must be shorter than 4 characters", + "In locale hr_HR, meridian must be shorter than 4 characters", + "In locale hr_HR, short month must be shorter than 5 characters", + "In locale sl_SI, meridian must be shorter than 4 characters", + "In locale sl_SI, meridian must be shorter than 4 characters", + "In locale ca_ES, long date output must be shorter than 15 characters (10 setembre 2024 -> 16)", + "In locale ca_ES, short month must be shorter than 5 characters", ]; /* These are warnings we know about but don't want in our output */ var KNOWN_WARNINGS = [ @@ -112,6 +120,104 @@ var KNOWN_WARNINGS = [ `In locale test, long time format might not work in some apps if it is not "%HH:%MM:%SS"`, `In locale wae_CH, short time format might not work in some apps if it is not "%HH:%MM"`, `In locale test, short time format might not work in some apps if it is not "%HH:%MM"`, + "App a_dndtoggle file a_dndtoggle.settings.js should be evaluated as a function but doesn't end in ')'", + "App activepedom file activepedom.settings.js should be evaluated as a function but doesn't end in ')'", + "App agpsdata file agpsdata.settings.js should be evaluated as a function but doesn't end in ')'", + "App alarm file alarm.settings.js should be evaluated as a function but doesn't end in ')'", + "App andark file andark.settings.js should be evaluated as a function but doesn't end in ')'", + "App antonclkplus file antonclkplus.settings.js should be evaluated as a function but doesn't end in ')'", + "App banglexercise file banglexercise.settings.js should be evaluated as a function but doesn't end in ')'", + "App barclock file barclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App berlinc file berlinc.settings.js should be evaluated as a function but doesn't end in ')'", + "App bikespeedo file bikespeedo.settings.js should be evaluated as a function but doesn't end in ')'", + "App blc file blc.settings.js should be evaluated as a function but doesn't end in ')'", + "App boxclk file boxclk.settings.js should be evaluated as a function but doesn't end in ')'", + "App bthome file bthome.clkinfo.js should be evaluated as a function but doesn't end in ')'", + "App bthrm file bthrm.settings.js should be evaluated as a function but doesn't end in ')'", + "App carcrazy file carcrazy.settings.js should be evaluated as a function but doesn't end in ')'", + "App chimer file chimer.settings.js should be evaluated as a function but doesn't end in ')'", + "App circlesclock file circlesclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App clicompleteclk file clicompleteclk.settings.js should be evaluated as a function but doesn't end in ')'", + "App clkinfocal file clkinfocal.settings.js should be evaluated as a function but doesn't end in ')'", + "App clkinfogps file gps.clkinfo.js should be evaluated as a function but doesn't end in ')'", + "App clkinfogpsspeed file clkinfogpsspeed.clkinfo.js should be evaluated as a function but doesn't end in ')'", + "App clkinfom file ram.clkinfo.js should be evaluated as a function but doesn't end in ')'", + "App clkinfomag file clkinfomag.clkinfo.js should be evaluated as a function but doesn't end in ')'", + "App clkinfostopw file stopw.clkinfo.js should be evaluated as a function but doesn't end in ')'", + "App clockcal file clockcal.settings.js should be evaluated as a function but doesn't end in ')'", + "App cogclock file cogclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App counter2 file counter2.settings.js should be evaluated as a function but doesn't end in ')'", + "App cprassist file cprassist.settings.js should be evaluated as a function but doesn't end in ')'", + "App dane_tcr file dane_tcr.settings.js should be evaluated as a function but doesn't end in ')'", + "App dragboard file dragboard.settings.js should be evaluated as a function but doesn't end in ')'", + "App draguboard file draguboard.settings.js should be evaluated as a function but doesn't end in ')'", + "App drained file drained.settings.js should be evaluated as a function but doesn't end in ')'", + "App drinkcounter file drinkcounter.settings.js should be evaluated as a function but doesn't end in ')'", + "App dtlaunch file dtlaunch.settings.js should be evaluated as a function but doesn't end in ')'", + "App ffcniftyb file ffcniftyb.settings.js should be evaluated as a function but doesn't end in ')'", + "App folderlaunch file folderlaunch.settings.js should be evaluated as a function but doesn't end in ')'", + "App gassist file gassist.settings.js should be evaluated as a function but doesn't end in ')'", + "App gbmusic file gbmusic.settings.js should be evaluated as a function but doesn't end in ')'", + "App getup file getup.settings.js should be evaluated as a function but doesn't end in ')'", + "App gipy file gipy.settings.js should be evaluated as a function but doesn't end in ')'", + "App gpsrec file gpsrec.settings.js should be evaluated as a function but doesn't end in ')'", + "App gpssetup file gpssetup.settings.js should be evaluated as a function but doesn't end in ')'", + "App iconlaunch file iconlaunch.settings.js should be evaluated as a function but doesn't end in ')'", + "App infoclk file infoclk.settings.js should be evaluated as a function but doesn't end in ')'", + "App largeclock file largeclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App launch file launch.settings.js should be evaluated as a function but doesn't end in ')'", + "App messagelist file messagelist.settings.js should be evaluated as a function but doesn't end in ')'", + "App messages file messages.settings.js should be evaluated as a function but doesn't end in ')'", + "App messages_light file messages_light.settings.js should be evaluated as a function but doesn't end in ')'", + "App messagesoverlay file messagesoverlay.settings.js should be evaluated as a function but doesn't end in ')'", + "App metronome file metronome.settings.js should be evaluated as a function but doesn't end in ')'", + "App multitimer file multitimer.settings.js should be evaluated as a function but doesn't end in ')'", + "App nesclock file nesclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App nightwatch file nightwatch.settings.js should be evaluated as a function but doesn't end in ')'", + "App owmweather file owmweather.settings.js should be evaluated as a function but doesn't end in ')'", + "App pebble file pebble.settings.js should be evaluated as a function but doesn't end in ')'", + "App pebbled file pebbled.settings.js should be evaluated as a function but doesn't end in ')'", + "App pongclock file pongclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App popconlaunch file popcon.settings.js should be evaluated as a function but doesn't end in ')'", + "App poweroff file poweroff.settings.js should be evaluated as a function but doesn't end in ')'", + "App puzzle15 file puzzle15.settings.js should be evaluated as a function but doesn't end in ')'", + "App qcenter file qcenter.settings.js should be evaluated as a function but doesn't end in ')'", + "App rebbleagenda file rebbleagenda.settings.js should be evaluated as a function but doesn't end in ')'", + "App recorder file recorder.clkinfo.js should be evaluated as a function but doesn't end in ')'", + "App rep file rep.settings.js should be evaluated as a function but doesn't end in ')'", + "App saclock file saclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App sched file sched.settings.js should be evaluated as a function but doesn't end in ')'", + "App score file score.settings.js should be evaluated as a function but doesn't end in ')'", + "App sensortools file sensortools.settings.js should be evaluated as a function but doesn't end in ')'", + "App shadowclk file shadowclk.settings.js should be evaluated as a function but doesn't end in ')'", + "App shortcuts file shortcuts.settings.js should be evaluated as a function but doesn't end in ')'", + "App simplebgclock file simplebgclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App slomoclock file slomoclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App slopeclockpp file slopeclockpp.settings.js should be evaluated as a function but doesn't end in ')'", + "App smclock file smclock.settings.js should be evaluated as a function but doesn't end in ')'", + "App speedalt file speedalt.settings.js should be evaluated as a function but doesn't end in ')'", + "App speedalt2 file speedalt2.settings.js should be evaluated as a function but doesn't end in ')'", + "App swp2clk file swp2clk.settings.js should be evaluated as a function but doesn't end in ')'", + "App taglaunch file taglaunch.settings.js should be evaluated as a function but doesn't end in ')'", + "App thunder file thunder.settings.js should be evaluated as a function but doesn't end in ')'", + "App timecal file timecal.settings.js should be evaluated as a function but doesn't end in ')'", + "App timerclk file timerclk.settings.js should be evaluated as a function but doesn't end in ')'", + "App timestamplog file timestamplog.settings.js should be evaluated as a function but doesn't end in ')'", + "App toucher file toucher.settings.js should be evaluated as a function but doesn't end in ')'", + "App touchtimer file touchtimer.settings.js should be evaluated as a function but doesn't end in ')'", + "App trex file trex.settings.js should be evaluated as a function but doesn't end in ')'", + "App usgs file usgs.settings.js should be evaluated as a function but doesn't end in ')'", + "App weatherClock file weatherClock.settings.js should be evaluated as a function but doesn't end in ')'", + "App wid_edit file wid_edit.settings.js should be evaluated as a function but doesn't end in ')'", + "App widalarmeta file widalarmeta.settings.js should be evaluated as a function but doesn't end in ')'", + "App widbaroalarm file widbaroalarm.settings.js should be evaluated as a function but doesn't end in ')'", + "App widbatwarn file widbatwarn.settings.js should be evaluated as a function but doesn't end in ')'", + "App widbgjs file widbgjs.settings.js should be evaluated as a function but doesn't end in ')'", + "App widdst file widdst.settings.js should be evaluated as a function but doesn't end in ')'", + "App widgps file widgps.settings.js should be evaluated as a function but doesn't end in ')'", + "App widhrm file widhrm.settings.js should be evaluated as a function but doesn't end in ')'", + "App widmp file widmp.settings.js should be evaluated as a function but doesn't end in ')'", + "App widsleepstatus file widsleepstatus.settings.js should be evaluated as a function but doesn't end in ')'", ]; var apps = []; @@ -181,6 +287,7 @@ const isGlob = f => /[?*]/.test(f) // All storage+data files in all apps: {app:,[file: | data:]} let allFiles = []; let existingApps = []; +let promise = Promise.resolve(); apps.forEach((app,appIdx) => { if (!app.id) ERROR(`App ${appIdx} has no id`); var appDirRelative = APPSDIR_RELATIVE+app.id+"/"; @@ -306,8 +413,9 @@ apps.forEach((app,appIdx) => { } if (file.name.endsWith(".js")) { // TODO: actual lint? + var ast; try { - acorn.parse(fileContents); + ast = acorn.parse(fileContents); } catch(e) { console.log("====================================================="); console.log(" PARSE OF "+appDir+file.url+" failed."); @@ -337,6 +445,18 @@ apps.forEach((app,appIdx) => { WARN(`Settings for ${app.id} has a boolean formatter - this is handled automatically, the line can be removed`, {file:appDirRelative+file.url, line: fileContents.substr(0, m.index).split("\n").length}); } } + // something that needs to be evaluated with 'eval(require("Storage").read(fn))' + if (/\.clkinfo\.js$/.test(file.name) || + /\.settings\.js$/.test(file.name)) { + if (!fileContents.trim().endsWith(")")) + WARN(`App ${app.id} file ${file.name} should be evaluated as a function but doesn't end in ')'`, {file:appDirRelative+file.url}); + } + if (/\.clkinfo\.js$/.test(file.name) || + /\.wid\.js$/.test(file.name)) { + if (fileContents.indexOf("g.clear(")>=0 || + fileContents.indexOf("g.reset().clear()")>=0) + ERROR(`App ${app.id} widget/clkinfo ${file.name} should never totally clear the screen`, {file:appDirRelative+file.url}); + } } for (const key in file) { if (!STORAGE_KEYS.includes(key)) ERROR(`App ${app.id} file ${file.name} has unknown key ${key}`, {file:appDirRelative+file.url}); @@ -436,6 +556,18 @@ apps.forEach((app,appIdx) => { ERROR(`App ${app.id} has provides_modules ${modulename} but it doesn't provide that filename`, {file:metadataFile}); }); } + /* + // We could try to create the files we need to upload for this app to check it all works ok... + promise = promise.then(() => apploader.getAppFiles(app).then(files => { + files.forEach(file => { + if (/\.clkinfo?\.js$/.test(file.name) || + /\.settings?\.js$/.test(file.name)) { + if (!file.content.startsWith("(")) { + ERROR(`App ${app.id} file ${file.name} should evaluate to a simple fn and doesn't (starts: ${JSON.stringify(file.content.substr(0,30))})`, {file:appDirRelative+file.url}); + } + } + }); + }));*/ }); @@ -481,12 +613,14 @@ function sanityCheckLocales(){ } } -console.log("=================================="); -console.log(`${errorCount} errors, ${warningCount} warnings (and ${knownErrorCount} known errors, ${knownWarningCount} known warnings)`); -console.log("=================================="); -if (errorCount) { - process.exit(1); -} else if ("CI" in process.env && warningCount) { - console.log("Running in CI, raising an error from warnings"); - process.exit(1); -} +promise.then(function() { + console.log("=================================="); + console.log(`${errorCount} errors, ${warningCount} warnings (and ${knownErrorCount} known errors, ${knownWarningCount} known warnings)`); + console.log("=================================="); + if (errorCount) { + process.exit(1); + } else if ("CI" in process.env && warningCount) { + console.log("Running in CI, raising an error from warnings"); + process.exit(1); + } +}); diff --git a/core b/core index 7e5ac0271..cbf53ec34 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 7e5ac0271f794bcacda3a5a692cfa479457eb4dd +Subproject commit cbf53ec34fee9b7d9234a7bbfc276592d9e076a5 diff --git a/modules/Layout.js b/modules/Layout.js index 639173f4d..5c66fc313 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -235,7 +235,7 @@ Layout.prototype.forgetLazyState = function () { Layout.prototype.layout = function (l) { // l = current layout element - var cb = { + var floor = Math.floor, cb = { "h" : function(l) {"ram"; var acc_w = l.x + (0|l.pad), accfillx = 0, @@ -246,7 +246,7 @@ Layout.prototype.layout = function (l) { c.x = 0|x; acc_w += c._w; accfillx += 0|c.fillx; - x = acc_w + 0|(accfillx*(l.w-l._w)/fillx); + x = acc_w + floor(accfillx*(l.w-l._w)/fillx); c.w = 0|(x - c.x); c.h = 0|(c.filly ? l.h - (l.pad<<1) : c._h); c.y = 0|(l.y + (0|l.pad) + ((1+(0|c.valign))*(l.h-(l.pad<<1)-c.h)>>1)); @@ -263,7 +263,7 @@ Layout.prototype.layout = function (l) { c.y = 0|y; acc_h += c._h; accfilly += 0|c.filly; - y = acc_h + 0|(accfilly*(l.h-l._h)/filly); + y = acc_h + floor(accfilly*(l.h-l._h)/filly); c.h = 0|(y - c.y); c.w = 0|(c.fillx ? l.w - (l.pad<<1) : c._w); c.x = 0|(l.x + (0|l.pad) + ((1+(0|c.halign))*(l.w-(l.pad<<1)-c.w)>>1)); @@ -363,4 +363,4 @@ Layout.prototype.clear = function(l) { g.clearRect(l.x,l.y,l.x+l.w-1,l.y+l.h-1); }; -exports = Layout; \ No newline at end of file +exports = Layout; diff --git a/modules/Layout.min.js b/modules/Layout.min.js index 8dd7f8c87..4c64d078a 100644 --- a/modules/Layout.min.js +++ b/modules/Layout.min.js @@ -1,14 +1,14 @@ -function p(d,k){function c(f){"ram";f.id&&(l[f.id]=f);f.type||(f.type="");f.c&&f.c.forEach(c)}this._l=this.l=d;this.options=k||{};this.lazy=this.options.lazy||!1;this.physBtns=1;let h;if(2!=process.env.HWVERSION){this.physBtns=3;h=[];function f(a){"ram";"btn"==a.type&&h.push(a);a.c&&a.c.forEach(f)}f(d);h.length&&(this.physBtns=0,this.buttons=h,this.selectedButton=-1)}if(this.options.btns)if(d=this.options.btns,this.physBtns>=d.length){this.b=d;let f=Math.floor(Bangle.appRect.h/ -this.physBtns);for(2d.length;)d.push({label:""});this._l.width=g.getWidth()-8;this._l={type:"h",filly:1,c:[this._l,{type:"v",pad:1,filly:1,c:d.map(a=>(a.type="txt",a.font="6x8",a.height=f,a.r=1,a))}]}}else this._l.width=g.getWidth()-32,this._l={type:"h",c:[this._l,{type:"v",c:d.map(f=>(f.type="btn",f.filly=1,f.width=32,f.r=1,f))}]},h&&h.push.apply(h,this._l.c[1].c);this.setUI();var l=this;c(this._l);this.updateNeeded=!0}function t(d, -k,c,h,l){var f=null==d.bgCol?l:g.toColor(d.bgCol);if(f!=l||"txt"==d.type||"btn"==d.type||"img"==d.type||"custom"==d.type){var a=d.c;delete d.c;var e="H"+E.CRC32(E.toJS(d));a&&(d.c=a);delete k[e]||((h[e]=[d.x,d.y,d.x+d.w-1,d.y+d.h-1]).bg=null==l?g.theme.bg:l,c&&(c.push(d),c=null))}if(d.c)for(var b of d.c)t(b,k,c,h,f)}p.prototype.setUI=function(){Bangle.setUI();let d;this.buttons&&(Bangle.setUI({mode:"updown",back:this.options.back,remove:this.options.remove},k=>{var c=this.selectedButton,h=this.buttons.length; -if(void 0===k&&this.buttons[c])return this.buttons[c].cb();this.buttons[c]&&(delete this.buttons[c].selected,this.render(this.buttons[c]));c=(c+h+k)%h;this.buttons[c]&&(this.buttons[c].selected=1,this.render(this.buttons[c]));this.selectedButton=c}),d=!0);!this.options.back&&!this.options.remove||d||Bangle.setUI({mode:"custom",back:this.options.back,remove:this.options.remove});if(this.b){function k(c,h){.75=c.x&&h.y>=c.y&&h.x<=c.x+c.w&&h.y<=c.y+c.h&&(2==h.type&&c.cbl?c.cbl(h):c.cb&&c.cb(h));c.c&&c.c.forEach(l=>k(l,h))}Bangle.touchHandler= -(c,h)=>k(this._l,h);Bangle.on("touch",Bangle.touchHandler)}};p.prototype.render=function(d){function k(b){"ram";c.reset();void 0!==b.col&&c.setColor(b.col);void 0!==b.bgCol&&c.setBgColor(b.bgCol).clearRect(b.x,b.y,b.x+b.w-1,b.y+b.h-1);h[b.type](b)}d||(d=this._l);this.updateNeeded&&this.update();var c=g,h={"":function(){},txt:function(b){"ram";if(b.wrap){var m=c.setFont(b.font).setFontAlign(0,-1).wrapString(b.label,b.w),n=b.y+(b.h-c.getFontHeight()*m.length>>1);c.drawString(m.join("\n"),b.x+(b.w>> -1),n)}else c.setFont(b.font).setFontAlign(0,0,b.r).drawString(b.label,b.x+(b.w>>1),b.y+(b.h>>1))},btn:function(b){"ram";var m=b.x+(0|b.pad),n=b.y+(0|b.pad),q=b.w-(b.pad<<1),r=b.h-(b.pad<<1);m=[m,n+4,m+4,n,m+q-5,n,m+q-1,n+4,m+q-1,n+r-5,m+q-5,n+r-1,m+4,n+r-1,m,n+r-5,m,n+4];n=void 0!==b.btnBorderCol?b.btnBorderCol:c.theme.fg2;q=void 0!==b.btnFaceCol?b.btnFaceCol:c.theme.bg2;b.selected&&(q=c.theme.bgH,n=c.theme.fgH);c.setColor(q).fillPoly(m).setColor(n).drawPoly(m);void 0!==b.col&&c.setColor(b.col);b.src? -c.setBgColor(q).drawImage("function"==typeof b.src?b.src():b.src,b.x+b.w/2,b.y+b.h/2,{scale:b.scale||void 0,rotate:.5*Math.PI*(b.r||0)}):c.setFont(b.font||"6x8:2").setFontAlign(0,0,b.r).drawString(b.label,b.x+b.w/2,b.y+b.h/2)},img:function(b){"ram";c.drawImage("function"==typeof b.src?b.src():b.src,b.x+b.w/2,b.y+b.h/2,{scale:b.scale||void 0,rotate:.5*Math.PI*(b.r||0)})},custom:function(b){"ram";b.render(b)},h:function(b){"ram";b.c.forEach(k)},v:function(b){"ram";b.c.forEach(k)}};if(this.lazy){this.rects|| -(this.rects={});var l=this.rects.clone(),f=[];t(d,l,f,this.rects,null);for(var a in l)delete this.rects[a];d=Object.keys(l).map(b=>l[b]).reverse();for(var e of d)c.setBgColor(e.bg).clearRect.apply(g,e);f.forEach(k)}else k(d)};p.prototype.forgetLazyState=function(){this.rects={}};p.prototype.layout=function(d){var k={h:function(c){"ram";var h=c.x+(0|c.pad),l=0,f=c.c&&c.c.reduce((e,b)=>e+(0|b.fillx),0);f||(h+=c.w-c._w>>1,f=1);var a=h;c.c.forEach(e=>{e.x=0|a;h+=e._w;l+=0|e.fillx;a=h+0|l*(c.w-c._w)/f; -e.w=0|a-e.x;e.h=0|(e.filly?c.h-(c.pad<<1):e._h);e.y=0|c.y+(0|c.pad)+((1+(0|e.valign))*(c.h-(c.pad<<1)-e.h)>>1);if(e.c)k[e.type](e)})},v:function(c){"ram";var h=c.y+(0|c.pad),l=0,f=c.c&&c.c.reduce((e,b)=>e+(0|b.filly),0);f||(h+=c.h-c._h>>1,f=1);var a=h;c.c.forEach(e=>{e.y=0|a;h+=e._h;l+=0|e.filly;a=h+0|l*(c.h-c._h)/f;e.h=0|a-e.y;e.w=0|(e.fillx?c.w-(c.pad<<1):e._w);e.x=0|c.x+(0|c.pad)+((1+(0|e.halign))*(c.w-(c.pad<<1)-e.w)>>1);if(e.c)k[e.type](e)})}};if(k[d.type])k[d.type](d)};p.prototype.debug=function(d, -k){d||(d=this._l);k=k||1;g.setColor(k&1,k&2,k&4).drawRect(d.x+k-1,d.y+k-1,d.x+d.w-k,d.y+d.h-k);d.pad&&g.drawRect(d.x+d.pad-1,d.y+d.pad-1,d.x+d.w-d.pad,d.y+d.h-d.pad);k++;d.c&&d.c.forEach(c=>this.debug(c,k))};p.prototype.update=function(){function d(a){"ram";l[a.type](a);if(a.r&1){var e=a._w;a._w=a._h;a._h=e}a._w=c(a._w+(a.pad<<1),0|a.width);a._h=c(a._h+(a.pad<<1),0|a.height)}delete this.updateNeeded;var k=g,c=Math.max,h=Math.round,l={txt:function(a){"ram";a.font.endsWith("%")&&(a.font="Vector"+h(k.getHeight()* -a.font.slice(0,-1)/100));if(a.wrap)a._h=a._w=0;else{var e=k.setFont(a.font).stringMetrics(a.label);a._w=e.width;a._h=e.height}},btn:function(a){"ram";a.font&&a.font.endsWith("%")&&(a.font="Vector"+h(k.getHeight()*a.font.slice(0,-1)/100));var e=a.src?k.imageMetrics("function"==typeof a.src?a.src():a.src):k.setFont(a.font||"6x8:2").stringMetrics(a.label);a._h=16+e.height;a._w=20+e.width},img:function(a){"ram";var e=k.imageMetrics("function"==typeof a.src?a.src():a.src),b=a.scale||1;a._w=e.width*b;a._h= -e.height*b},"":function(a){"ram";a._w=0;a._h=0},custom:function(a){"ram";a._w=0;a._h=0},h:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,b)=>c(e,b._h),0);a._w=a.c.reduce((e,b)=>e+b._w,0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)},v:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,b)=>e+b._h,0);a._w=a.c.reduce((e,b)=>c(e,b._w),0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)}},f=this._l; -d(f);delete l;f.fillx||f.filly?(f.w=Bangle.appRect.w,f.h=Bangle.appRect.h,f.x=Bangle.appRect.x,f.y=Bangle.appRect.y):(f.w=f._w,f.h=f._h,f.x=Bangle.appRect.w-f.w>>1,f.y=Bangle.appRect.y+(Bangle.appRect.h-f.h>>1));this.layout(f)};p.prototype.clear=function(d){d||(d=this._l);g.reset();void 0!==d.bgCol&&g.setBgColor(d.bgCol);g.clearRect(d.x,d.y,d.x+d.w-1,d.y+d.h-1)};exports=p \ No newline at end of file +function p(c,h){function d(f){"ram";f.id&&(l[f.id]=f);f.type||(f.type="");f.c&&f.c.forEach(d)}this._l=this.l=c;this.options=h||{};this.lazy=this.options.lazy||!1;this.physBtns=1;let e;if(2!=process.env.HWVERSION){this.physBtns=3;e=[];function f(b){"ram";"btn"==b.type&&e.push(b);b.c&&b.c.forEach(f)}f(c);e.length&&(this.physBtns=0,this.buttons=e,this.selectedButton=-1)}if(this.options.btns)if(c=this.options.btns,this.physBtns>=c.length){this.b=c;let f=Math.floor(Bangle.appRect.h/ +this.physBtns);for(2c.length;)c.push({label:""});this._l.width=g.getWidth()-8;this._l={type:"h",filly:1,c:[this._l,{type:"v",pad:1,filly:1,c:c.map(b=>(b.type="txt",b.font="6x8",b.height=f,b.r=1,b))}]}}else this._l.width=g.getWidth()-32,this._l={type:"h",c:[this._l,{type:"v",c:c.map(f=>(f.type="btn",f.filly=1,f.width=32,f.r=1,f))}]},e&&e.push.apply(e,this._l.c[1].c);this.setUI();var l=this;d(this._l);this.updateNeeded=!0}function t(c, +h,d,e,l){var f=null==c.bgCol?l:g.toColor(c.bgCol);if(f!=l||"txt"==c.type||"btn"==c.type||"img"==c.type||"custom"==c.type){var b=c.c;delete c.c;var k="H"+E.CRC32(E.toJS(c));b&&(c.c=b);delete h[k]||((e[k]=[c.x,c.y,c.x+c.w-1,c.y+c.h-1]).bg=null==l?g.theme.bg:l,d&&(d.push(c),d=null))}if(c.c)for(var a of c.c)t(a,h,d,e,f)}p.prototype.setUI=function(){Bangle.setUI();let c;this.buttons&&(Bangle.setUI({mode:"updown",back:this.options.back,remove:this.options.remove},h=>{var d=this.selectedButton,e=this.buttons.length; +if(void 0===h&&this.buttons[d])return this.buttons[d].cb();this.buttons[d]&&(delete this.buttons[d].selected,this.render(this.buttons[d]));d=(d+e+h)%e;this.buttons[d]&&(this.buttons[d].selected=1,this.render(this.buttons[d]));this.selectedButton=d}),c=!0);!this.options.back&&!this.options.remove||c||Bangle.setUI({mode:"custom",back:this.options.back,remove:this.options.remove});if(this.b){function h(d,e){.75=d.x&&e.y>=d.y&&e.x<=d.x+d.w&&e.y<=d.y+d.h&&(2==e.type&&d.cbl?d.cbl(e):d.cb&&d.cb(e));d.c&&d.c.forEach(l=>h(l,e))}Bangle.touchHandler= +(d,e)=>h(this._l,e);Bangle.on("touch",Bangle.touchHandler)}};p.prototype.render=function(c){function h(a){"ram";d.reset();void 0!==a.col&&d.setColor(a.col);void 0!==a.bgCol&&d.setBgColor(a.bgCol).clearRect(a.x,a.y,a.x+a.w-1,a.y+a.h-1);e[a.type](a)}c||(c=this._l);this.updateNeeded&&this.update();var d=g,e={"":function(){},txt:function(a){"ram";if(a.wrap){var m=d.setFont(a.font).setFontAlign(0,-1).wrapString(a.label,a.w),n=a.y+(a.h-d.getFontHeight()*m.length>>1);d.drawString(m.join("\n"),a.x+(a.w>> +1),n)}else d.setFont(a.font).setFontAlign(0,0,a.r).drawString(a.label,a.x+(a.w>>1),a.y+(a.h>>1))},btn:function(a){"ram";var m=a.x+(0|a.pad),n=a.y+(0|a.pad),q=a.w-(a.pad<<1),r=a.h-(a.pad<<1);m=[m,n+4,m+4,n,m+q-5,n,m+q-1,n+4,m+q-1,n+r-5,m+q-5,n+r-1,m+4,n+r-1,m,n+r-5,m,n+4];n=void 0!==a.btnBorderCol?a.btnBorderCol:d.theme.fg2;q=void 0!==a.btnFaceCol?a.btnFaceCol:d.theme.bg2;a.selected&&(q=d.theme.bgH,n=d.theme.fgH);d.setColor(q).fillPoly(m).setColor(n).drawPoly(m);void 0!==a.col&&d.setColor(a.col);a.src? +d.setBgColor(q).drawImage("function"==typeof a.src?a.src():a.src,a.x+a.w/2,a.y+a.h/2,{scale:a.scale||void 0,rotate:.5*Math.PI*(a.r||0)}):d.setFont(a.font||"6x8:2").setFontAlign(0,0,a.r).drawString(a.label,a.x+a.w/2,a.y+a.h/2)},img:function(a){"ram";d.drawImage("function"==typeof a.src?a.src():a.src,a.x+a.w/2,a.y+a.h/2,{scale:a.scale||void 0,rotate:.5*Math.PI*(a.r||0)})},custom:function(a){"ram";a.render(a)},h:function(a){"ram";a.c.forEach(h)},v:function(a){"ram";a.c.forEach(h)}};if(this.lazy){this.rects|| +(this.rects={});var l=this.rects.clone(),f=[];t(c,l,f,this.rects,null);for(var b in l)delete this.rects[b];c=Object.keys(l).map(a=>l[a]).reverse();for(var k of c)d.setBgColor(k.bg).clearRect.apply(g,k);f.forEach(h)}else h(c)};p.prototype.forgetLazyState=function(){this.rects={}};p.prototype.layout=function(c){var h=Math.floor,d={h:function(e){"ram";var l=e.x+(0|e.pad),f=0,b=e.c&&e.c.reduce((a,m)=>a+(0|m.fillx),0);b||(l+=e.w-e._w>>1,b=1);var k=l;e.c.forEach(a=>{a.x=0|k;l+=a._w;f+=0|a.fillx;k=l+h(f* +(e.w-e._w)/b);a.w=0|k-a.x;a.h=0|(a.filly?e.h-(e.pad<<1):a._h);a.y=0|e.y+(0|e.pad)+((1+(0|a.valign))*(e.h-(e.pad<<1)-a.h)>>1);if(a.c)d[a.type](a)})},v:function(e){"ram";var l=e.y+(0|e.pad),f=0,b=e.c&&e.c.reduce((a,m)=>a+(0|m.filly),0);b||(l+=e.h-e._h>>1,b=1);var k=l;e.c.forEach(a=>{a.y=0|k;l+=a._h;f+=0|a.filly;k=l+h(f*(e.h-e._h)/b);a.h=0|k-a.y;a.w=0|(a.fillx?e.w-(e.pad<<1):a._w);a.x=0|e.x+(0|e.pad)+((1+(0|a.halign))*(e.w-(e.pad<<1)-a.w)>>1);if(a.c)d[a.type](a)})}};if(d[c.type])d[c.type](c)};p.prototype.debug= +function(c,h){c||(c=this._l);h=h||1;g.setColor(h&1,h&2,h&4).drawRect(c.x+h-1,c.y+h-1,c.x+c.w-h,c.y+c.h-h);c.pad&&g.drawRect(c.x+c.pad-1,c.y+c.pad-1,c.x+c.w-c.pad,c.y+c.h-c.pad);h++;c.c&&c.c.forEach(d=>this.debug(d,h))};p.prototype.update=function(){function c(b){"ram";l[b.type](b);if(b.r&1){var k=b._w;b._w=b._h;b._h=k}b._w=d(b._w+(b.pad<<1),0|b.width);b._h=d(b._h+(b.pad<<1),0|b.height)}delete this.updateNeeded;var h=g,d=Math.max,e=Math.round,l={txt:function(b){"ram";b.font.endsWith("%")&&(b.font= +"Vector"+e(h.getHeight()*b.font.slice(0,-1)/100));if(b.wrap)b._h=b._w=0;else{var k=h.setFont(b.font).stringMetrics(b.label);b._w=k.width;b._h=k.height}},btn:function(b){"ram";b.font&&b.font.endsWith("%")&&(b.font="Vector"+e(h.getHeight()*b.font.slice(0,-1)/100));var k=b.src?h.imageMetrics("function"==typeof b.src?b.src():b.src):h.setFont(b.font||"6x8:2").stringMetrics(b.label);b._h=16+k.height;b._w=20+k.width},img:function(b){"ram";var k=h.imageMetrics("function"==typeof b.src?b.src():b.src),a=b.scale|| +1;b._w=k.width*a;b._h=k.height*a},"":function(b){"ram";b._w=0;b._h=0},custom:function(b){"ram";b._w=0;b._h=0},h:function(b){"ram";b.c.forEach(c);b._h=b.c.reduce((k,a)=>d(k,a._h),0);b._w=b.c.reduce((k,a)=>k+a._w,0);null==b.fillx&&b.c.some(k=>k.fillx)&&(b.fillx=1);null==b.filly&&b.c.some(k=>k.filly)&&(b.filly=1)},v:function(b){"ram";b.c.forEach(c);b._h=b.c.reduce((k,a)=>k+a._h,0);b._w=b.c.reduce((k,a)=>d(k,a._w),0);null==b.fillx&&b.c.some(k=>k.fillx)&&(b.fillx=1);null==b.filly&&b.c.some(k=>k.filly)&& +(b.filly=1)}},f=this._l;c(f);delete l;f.fillx||f.filly?(f.w=Bangle.appRect.w,f.h=Bangle.appRect.h,f.x=Bangle.appRect.x,f.y=Bangle.appRect.y):(f.w=f._w,f.h=f._h,f.x=Bangle.appRect.w-f.w>>1,f.y=Bangle.appRect.y+(Bangle.appRect.h-f.h>>1));this.layout(f)};p.prototype.clear=function(c){c||(c=this._l);g.reset();void 0!==c.bgCol&&g.setBgColor(c.bgCol);g.clearRect(c.x,c.y,c.x+c.w-1,c.y+c.h-1)};exports=p \ No newline at end of file diff --git a/modules/time_utils.js b/modules/time_utils.js index 6a3ed6faf..0f503ad37 100644 --- a/modules/time_utils.js +++ b/modules/time_utils.js @@ -13,18 +13,13 @@ // Note that if a field is undefined then its value is zero. // -const ONE_SECOND = 1000; -const ONE_MINUTE = 60 * ONE_SECOND; -const ONE_HOUR = 60 * ONE_MINUTE; -const ONE_DAY = 24 * ONE_HOUR; - /** * @param {object} time {d, h, m, s} * @returns the milliseconds contained in the passed time object */ exports.encodeTime = (time) => { time = safeTime(time); - return time.d * ONE_DAY + time.h * ONE_HOUR + time.m * ONE_MINUTE + time.s * ONE_SECOND; + return time.d * 86400000 + time.h * 3600000 + time.m * 60000 + time.s * 1000; } // internal use, set to zero all the undefined fields @@ -38,26 +33,26 @@ function safeTime(time) { */ exports.decodeTime = (millis) => { if (typeof millis !== "number") throw "Only a number can be decoded"; - var d = Math.floor(millis / ONE_DAY); - millis -= d * ONE_DAY; - var h = Math.floor(millis / ONE_HOUR); - millis -= h * ONE_HOUR; - var m = Math.floor(millis / ONE_MINUTE); - millis -= m * ONE_MINUTE; - var s = Math.floor(millis / ONE_SECOND); + var d = Math.floor(millis / 86400000); + millis -= d * 86400000; + var h = Math.floor(millis / 3600000); + millis -= h * 3600000; + var m = Math.floor(millis / 60000); + millis -= m * 60000; + var s = Math.floor(millis / 1000); return { d: d, h: h, m: m, s: s }; } -/** +/** * @param {object|int} value {h, m} object or milliseconds * @returns an human-readable time string like "10:25" * @throws an exception if d != 0 or h > 23 or m > 59 */ exports.formatTime = (value) => { var time = safeTime(typeof value === "object" ? value : exports.decodeTime(value)); - if (time.d != 0) throw "days not supported here"; - if (time.h < 0 || time.h > 23) throw "Invalid value: must be 0 <= h <= 23"; - if (time.m < 0 || time.m > 59) throw "Invalid value: must be 0 <= m <= 59"; + time.h += time.d*24; + /*if (time.h < 0 || time.h > 23) throw "Invalid value: must be 0 <= h <= 23"; + if (time.m < 0 || time.m > 59) throw "Invalid value: must be 0 <= m <= 59";*/ return time.h + ":" + ("0" + time.m).substr(-2); }