diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e2fbf5609..a20c7ed7c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,3 +5,5 @@ updates: directory: "/" schedule: interval: "daily" + reviewers: + - "gfwilliams" diff --git a/README.md b/README.md index d595c7df1..ddcf23f25 100644 --- a/README.md +++ b/README.md @@ -289,6 +289,7 @@ and which gives information about the app for the Launcher. "dependencies" : { "message":"widget" } // optional, depend on a specific type of widget - see provides_widgets "provides_modules" : ["messageicons"] // optional, this app provides a module that can be used with 'require' "provides_widgets" : ["battery"] // optional, this app provides a type of widget - 'alarm/battery/bluetooth/pedometer/message' + "provides_features" : ["welcome"] // optional, this app provides some feature, used to ensure two aren't installed at once. Currently just 'welcome' "default" : true, // set if an app is the default implementer of something (a widget/module/etc) "readme": "README.md", // if supplied, a link to a markdown-style text file // that contains more information about this app (usage, etc) diff --git a/apps/agenda/ChangeLog b/apps/agenda/ChangeLog index d1b95a702..cb60537e6 100644 --- a/apps/agenda/ChangeLog +++ b/apps/agenda/ChangeLog @@ -15,3 +15,4 @@ 0.13: Show day of the week in date 0.14: Fixed "Today" and "Yesterday" wrongly displayed for allDay events on some time zones 0.15: Minor code improvements +0.16: Correct date for all day events in negative timezones, improve locale display diff --git a/apps/agenda/agenda.js b/apps/agenda/agenda.js index 4f3a91537..914ff0217 100644 --- a/apps/agenda/agenda.js +++ b/apps/agenda/agenda.js @@ -30,11 +30,16 @@ var settings = require("Storage").readJSON("agenda.settings.json",true)||{}; CALENDAR=CALENDAR.sort((a,b)=>a.timestamp - b.timestamp); -function getDate(timestamp) { - return new Date(timestamp*1000); +function getDate(timestamp, allDay) { + // All day events are always in UTC and always start at 00:00:00, so we + // need to "undo" the timezone offsetting to make sure that the day is + // correct. + var offset = allDay ? new Date().getTimezoneOffset() * 60 : 0 + return new Date((timestamp+offset)*1000); } + function formatDay(date) { - let formattedDate = Locale.dow(date,1) + " " + Locale.date(date).replace(/\d\d\d\d/,""); + let formattedDate = Locale.dow(date,1) + " " + Locale.date(date).replace(/,*\s*\d\d\d\d/,""); if (!settings.useToday) { return formattedDate; } @@ -57,8 +62,9 @@ function formatDateLong(date, includeDay, allDay) { } return shortTime; } + function formatDateShort(date, allDay) { - return formatDay(date)+(allDay?"":Locale.time(date,1)+Locale.meridian(date)); + return formatDay(date)+(allDay?"":" "+Locale.time(date,1)+Locale.meridian(date)); } var lines = []; @@ -69,16 +75,19 @@ function showEvent(ev) { //var lines = []; if (ev.title) lines = g.wrapString(ev.title, g.getWidth()-10); var titleCnt = lines.length; - var start = getDate(ev.timestamp); - var end = getDate((+ev.timestamp) + (+ev.durationInSeconds)); + var start = getDate(ev.timestamp, ev.allDay); + // All day events end at the midnight boundary of the following day. Here, we + // subtract one second for all day events so the days display correctly. + const allDayEndCorrection = ev.allDay ? 1 : 0; + var end = getDate((+ev.timestamp) + (+ev.durationInSeconds) - allDayEndCorrection, ev.allDay); var includeDay = true; if (titleCnt) lines.push(""); // add blank line after title if(start.getDay() == end.getDay() && start.getMonth() == end.getMonth()) includeDay = false; - if(includeDay && ev.allDay) { - //single day all day (average to avoid getting previous day) + if(!includeDay && ev.allDay) { + //single day all day lines = lines.concat( - g.wrapString(formatDateLong(new Date((start+end)/2), includeDay, ev.allDay), g.getWidth()-10)); + g.wrapString(formatDateLong(start, includeDay, ev.allDay), g.getWidth()-10)); } else if(includeDay || ev.allDay) { lines = lines.concat( /*LANG*/"Start"+":", @@ -137,7 +146,7 @@ function showList() { if (!ev) return; var isPast = false; var x = r.x+2, title = ev.title; - var body = formatDateShort(getDate(ev.timestamp),ev.allDay)+"\n"+(ev.location?ev.location:/*LANG*/"No location"); + var body = formatDateShort(getDate(ev.timestamp, ev.allDay),ev.allDay)+"\n"+(ev.location?ev.location:/*LANG*/"No location"); if(settings.pastEvents) isPast = ev.timestamp + ev.durationInSeconds < (new Date())/1000; if (title) g.setFontAlign(-1,-1).setFont(fontBig) .setColor(isPast ? "#888" : g.theme.fg).drawString(title, x+4,r.y+2); diff --git a/apps/agenda/metadata.json b/apps/agenda/metadata.json index 65993609e..c3e238567 100644 --- a/apps/agenda/metadata.json +++ b/apps/agenda/metadata.json @@ -1,7 +1,7 @@ { "id": "agenda", "name": "Agenda", - "version": "0.15", + "version": "0.16", "description": "Simple agenda", "icon": "agenda.png", "screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}], diff --git a/apps/alpinenav/README.md b/apps/alpinenav/README.md index d18cdfd6d..823d6c9f8 100644 --- a/apps/alpinenav/README.md +++ b/apps/alpinenav/README.md @@ -2,13 +2,26 @@ Alpine Navigator ================ App that performs GPS monitoring to track and display position relative to a given origin in realtime. -![screenshot](./sample.png) +![screenshot](./sample.png) + + [compass 5] + + altitude +[start 1] [current 2] + + distance +[from start 3] [track 4] + + +[btn1 -- screen lock] +[btn2 -- remove points] +[btn3 -- pause] Functions --------- -Note if you've not used GPS yet I suggest using one of the GPS apps to get your first fix and confirm as I've found that helps initially. +Note if you've not used GPS yet, I suggest using one of the GPS apps to get your first fix and confirm, as I've found that helps initially. -The GPS and magnetometer will be turned on and after a few moments, when the watch buzzes and the dot turns from red to pink, that means the GPS is fixed. all your movements now will be displayed with a line drawn back to show your position relative to the start. New waypoints will be added based on checking every 10 seconds for at least 5 meters of movement. The map will scale to your distance travelled so the route will always remain within the window, the accelerometer/pedometer is not used - this is a purely GPS and compass solution so can be used for driving/cycling etc. A log file will be recorded that tracks upto 1000 waypoints, this isn't a big file and you could remove the limit but I've kept it fairly conservative here as it's not intended as a main feature, there's already good GPS recorders for the Bangle. The following other items are displayed: +The GPS and magnetometer will be turned on and after a few moments, when the watch buzzes and the dot turns from red to pink, that means the GPS is fixed. All your movements now will be displayed with a line drawn back to show your position relative to the start. New waypoints will be added based on checking every 10 seconds for at least 5 meters of movement. The map will scale to your distance travelled so the route will always remain within the window, the accelerometer/pedometer is not used - this is a purely GPS and compass solution so can be used for driving/cycling etc. A log file will be recorded that tracks upto 1000 waypoints, this isn't a big file and you could remove the limit, but I've kept it fairly conservative here, as it's not intended as a main feature, there's already good GPS recorders for the Bangle. The following other items are displayed: 1. altitude at origin, this is displayed left of the centre. 2. current altitude, displayed centre right @@ -16,12 +29,12 @@ The GPS and magnetometer will be turned on and after a few moments, when the wat 4. distance travelled, bottom right (meters) 5. compass heading, at the top -For the display, the route is kept at a set resolution, so there's no risk of running into memory problems if you run this for long periods or any length of time because the waypoints will be reduced when it reaches a set threshold so you may see the path smooth out slightly at intervals. +For the display, the route is kept at a set resolution, so there's no risk of running into memory problems if you run this for long periods or any length of time, because the waypoints will be reduced when it reaches a set threshold, so you may see the path smooth out slightly at intervals. -If you get strange values or dashes for the compass, it just needs calibration so you need to move the watch around briefly for this each time, ideally 360 degrees around itself, which involves taking the watch off. If you don't want to do that you can also just wave your hand around for a few seconds like you're at a rave or Dr Strange making a Sling Ring but often just moving your wrist a bit is enough. +If you get strange values or dashes for the compass, it just needs calibration so you need to move the watch around briefly for this each time, ideally 360 degrees around itself, which involves taking the watch off. If you don't want to do that you can also just wave your hand around for a few seconds like you're at a rave or Dr Strange making a Sling Ring, but often just moving your wrist a bit is enough. The buttons do the following: -BTN1: this will display an 'X' in the bottom of the screen and lock all the buttons, this is to prevent you accidentally pressing either of the below. Remember to press this again to unlock it! soft and hard reset will both still work. +BTN1: this will display an 'X' in the bottom of the screen and lock all the buttons, this is to prevent you accidentally pressing either of the below. Remember to press this again to unlock it! Soft and hard reset will both still work. BTN2: this removes all waypoints aside from the origin and your current location; sometimes during smaller journeys and walks, the GPS can give sporadic differences in locations because of the error margins of GPS and this can add noise to your route. BTN3: this will pause the GPS and magnetometer, useful for saving power for situations where you don't necessarily need to track parts of your route e.g. you're going indoors/shelter for some time. You'll know it's paused because the compass won't update it's reading and all the metrics will be blacked out on the screen. diff --git a/apps/andark/ChangeLog b/apps/andark/ChangeLog index 7d7f9567b..fa89d5618 100644 --- a/apps/andark/ChangeLog +++ b/apps/andark/ChangeLog @@ -5,3 +5,5 @@ 0.05: Fix support for dark theme + support widgets + add settings for widgets, order of drawing and hour hand length 0.06: Fix issue showing widgets when app is fast-loaded into from launcher with widgets disabled +0.07: Enable fast loading and queue updates to the second +0.08: Restore redraw on charging event + fixup for safer fast-loading diff --git a/apps/andark/app.js b/apps/andark/app.js index e6b5204f0..81d757ce4 100644 --- a/apps/andark/app.js +++ b/apps/andark/app.js @@ -1,3 +1,4 @@ +{ const defaultSettings = { loadWidgets : false, textAboveHands : false, @@ -11,9 +12,9 @@ const zahlpos=(function() { let z=[]; let sk=1; for(let i=-10;i<50;i+=5){ - let win=i*2*Math.PI/60; - let xsk =c.x+2+Math.cos(win)*(c.x-10), - ysk =c.y+2+Math.sin(win)*(c.x-10); + let win=i*2*Math.PI/60; + let xsk =c.x+2+Math.cos(win)*(c.x-10), + ysk =c.y+2+Math.sin(win)*(c.x-10); if(sk==3){xsk-=10;} if(sk==6){ysk-=10;} if(sk==9){xsk+=10;} @@ -25,18 +26,15 @@ const zahlpos=(function() { return z; })(); -let unlock = false; - -function zeiger(len,dia,tim){ +const zeiger = function(len,dia,tim) { const x=c.x+ Math.cos(tim)*len/2, y=c.y + Math.sin(tim)*len/2, d={"d":3,"x":dia/2*Math.cos(tim+Math.PI/2),"y":dia/2*Math.sin(tim+Math.PI/2)}, pol=[c.x-d.x,c.y-d.y,c.x+d.x,c.y+d.y,x+d.x,y+d.y,x-d.x,y-d.y]; return pol; +}; -} - -function drawHands(d) { +const drawHands = function(d) { let m=d.getMinutes(), h=d.getHours(), s=d.getSeconds(); g.setColor(1,1,1); @@ -61,32 +59,60 @@ function drawHands(d) { g.fillPoly(sekz,true); } g.fillCircle(c.x,c.y,4); -} +}; -function drawText(d) { +const drawText = function(d) { g.setFont("Vector",10); g.setBgColor(0,0,0); g.setColor(1,1,1); - let dateStr = require("locale").date(d); + const dateStr = require("locale").date(d); g.drawString(dateStr, c.x, c.y+20, true); - let batStr = Math.round(E.getBattery()/5)*5+"%"; + const batStr = Math.round(E.getBattery()/5)*5+"%"; if (Bangle.isCharging()) { g.setBgColor(1,0,0); } g.drawString(batStr, c.x, c.y+40, true); -} +}; -function drawNumbers() { +const drawNumbers = function() { //draws the numbers on the screen g.setFont("Vector",20); g.setColor(1,1,1); g.setBgColor(0,0,0); for(let i = 0;i<12;i++){ - g.drawString(zahlpos[i][0],zahlpos[i][1],zahlpos[i][2],true); + g.drawString(zahlpos[i][0],zahlpos[i][1],zahlpos[i][2],true); } -} +}; -function draw(){ +let drawTimeout; +let queueMillis = 1000; +let unlock = true; + +const updateState = function() { + if (Bangle.isLCDOn()) { + if (!Bangle.isLocked()) { + queueMillis = 1000; + unlock = true; + } else { + queueMillis = 60000; + unlock = false; + } + draw(); + } else { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}; + +const queueDraw = function() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, queueMillis - (Date.now() % queueMillis)); +}; + +const draw = function() { // draw black rectangle in the middle to clear screen from scale and hands g.setColor(0,0,0); g.fillRect(10,10,2*c.x-10,2*c.x-10); @@ -100,10 +126,11 @@ function draw(){ } else { drawText(d); drawHands(d); } -} + queueDraw(); +}; //draws the scale once the app is startet -function drawScale(){ +const drawScale = function() { // clear the screen g.setBgColor(0,0,0); g.clear(); @@ -117,36 +144,35 @@ function drawScale(){ g.fillRect(10,10,2*c.x-10,2*c.x-10); g.setColor(1,1,1); } -} +}; //// main running sequence //// // Show launcher when middle button pressed, and widgets that we're clock -Bangle.setUI("clock"); +Bangle.setUI({ + mode: "clock", + remove: function() { + Bangle.removeListener('lcdPower', updateState); + Bangle.removeListener('lock', updateState); + Bangle.removeListener('charging', draw); + // We clear drawTimout after removing all listeners, because they can add one again + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + require("widget_utils").show(); + } +}); // Load widgets if needed, and make them show swipeable if (settings.loadWidgets) { Bangle.loadWidgets(); require("widget_utils").swipeOn(); } else if (global.WIDGETS) require("widget_utils").hide(); -// Clear the screen once, at startup -drawScale(); -draw(); - -let secondInterval = setInterval(draw, 1000); // Stop updates when LCD is off, restart when on -Bangle.on('lcdPower',on=>{ - if (secondInterval) clearInterval(secondInterval); - secondInterval = undefined; - if (on) { - secondInterval = setInterval(draw, 1000); - draw(); // draw immediately - } -}); -Bangle.on('lock',on=>{ - unlock = !on; - if (secondInterval) clearInterval(secondInterval); - secondInterval = setInterval(draw, unlock ? 1000 : 60000); - draw(); // draw immediately -}); -Bangle.on('charging',on=>{draw();}); +Bangle.on('lcdPower', updateState); +Bangle.on('lock', updateState); +Bangle.on('charging', draw); // Immediately redraw when charger (dis)connected + +updateState(); +drawScale(); +draw(); +} diff --git a/apps/andark/metadata.json b/apps/andark/metadata.json index fc8872f4b..4bd88b3f5 100644 --- a/apps/andark/metadata.json +++ b/apps/andark/metadata.json @@ -1,7 +1,7 @@ { "id": "andark", "name": "Analog Dark", "shortName":"AnDark", - "version":"0.06", + "version":"0.08", "description": "analog clock face without disturbing widgets", "icon": "andark_icon.png", "type": "clock", diff --git a/apps/assistedgps/custom.html b/apps/assistedgps/custom.html index a51219346..39290c2e6 100644 --- a/apps/assistedgps/custom.html +++ b/apps/assistedgps/custom.html @@ -49,7 +49,7 @@ BDS+GLONASS diff --git a/apps/ateatimer/ChangeLog b/apps/ateatimer/ChangeLog new file mode 100644 index 000000000..81da9fdce --- /dev/null +++ b/apps/ateatimer/ChangeLog @@ -0,0 +1,2 @@ +0.01: First release +0.02: Fix icon, utilize sched, show running timer on app relaunch \ No newline at end of file diff --git a/apps/ateatimer/app-icon.js b/apps/ateatimer/app-icon.js new file mode 100644 index 000000000..f80208ead --- /dev/null +++ b/apps/ateatimer/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgIKHgwFKo0gAofmsALEGR0H/+f//+gEP/4ACAoXAn4FDAQn8g0DAoX4g0BAoXx4E4AoXhAoN/8EP4AzBn/4h/IC4M//kPzgjBz/+h+MAoMfj0PNYUfh4FDh8HAo0wg/454RBmBDBAoRnBCIIjCAAMPF4IFDHYOIgEBj5HBzkAIIPAIIIFBn4hBLIU+AoPgwEQvwFBOIX8CgP5w0RAoSJC/AsB/0EJwIgB/+Aj/wAoN/VgPgQwQFBwBKCXAQWBAAfgAoocCAoQcCAAPAj7XEcYIABcYLIBAAJBBA==")) \ No newline at end of file diff --git a/apps/ateatimer/app.js b/apps/ateatimer/app.js new file mode 100644 index 000000000..9322d4e46 --- /dev/null +++ b/apps/ateatimer/app.js @@ -0,0 +1,156 @@ +// Tea Timer Application for Bangle.js 2 using sched library + +let timerDuration = (() => { + let file = require("Storage").open("ateatimer.data", "r"); + let data = file.read(4); // Assuming 4 bytes for storage + return data ? parseInt(data, 10) : 4 * 60; // Default to 4 minutes +})(); +let timeRemaining = timerDuration; +let timerRunning = false; + +function saveDefaultDuration() { + let file = require("Storage").open("ateatimer.data", "w"); + file.write(timerDuration.toString()); +} + +function drawTime() { + g.clear(); + g.setFont("Vector", 40); + g.setFontAlign(0, 0); // Center align + + const minutes = Math.floor(Math.abs(timeRemaining) / 60); + const seconds = Math.abs(timeRemaining) % 60; + const sign = timeRemaining < 0 ? "-" : ""; + const timeStr = `${sign}${minutes}:${seconds.toString().padStart(2, '0')}`; + + g.drawString(timeStr, g.getWidth() / 2, g.getHeight() / 2); + + // Draw Increase button (triangle pointing up) + g.fillPoly([ + g.getWidth() / 2, g.getHeight() / 2 - 80, // Top vertex + g.getWidth() / 2 - 20, g.getHeight() / 2 - 60, // Bottom-left vertex + g.getWidth() / 2 + 20, g.getHeight() / 2 - 60 // Bottom-right vertex + ]); + + // Draw Decrease button (triangle pointing down) + g.fillPoly([ + g.getWidth() / 2, g.getHeight() / 2 + 80, // Bottom vertex + g.getWidth() / 2 - 20, g.getHeight() / 2 + 60, // Top-left vertex + g.getWidth() / 2 + 20, g.getHeight() / 2 + 60 // Top-right vertex + ]); + + g.flip(); +} + +function startTimer() { + if (timerRunning) return; + if (timeRemaining == 0) return; + timerRunning = true; + + // Save the default duration on timer start + timerDuration = timeRemaining; + saveDefaultDuration(); + scheduleTimer(); + + // Start the secondary timer to update the display + setInterval(updateDisplay, 1000); +} + +function scheduleTimer() { + // Schedule a new timer using the sched library + require("sched").setAlarm("ateatimer", { + msg: "Tea is ready!", + timer: timeRemaining * 1000, // Convert to milliseconds + vibrate: ".." // Default vibration pattern + }); + + // Ensure the scheduler updates + require("sched").reload(); +} + +function resetTimer() { + // Cancel the existing timer + require("sched").setAlarm("ateatimer", undefined); + require("sched").reload(); + + timerRunning = false; + timeRemaining = timerDuration; + drawTime(); +} + +function adjustTime(amount) { + if (-amount > timeRemaining) { + // Return if result will be negative + return; + } + timeRemaining += amount; + timeRemaining = Math.max(0, timeRemaining); // Ensure time doesn't go negative + if (timerRunning) { + // Update the existing timer with the new remaining time + let alarm = require("sched").getAlarm("ateatimer"); + if (alarm) { + // Cancel the current alarm + require("sched").setAlarm("ateatimer", undefined); + + // Set a new alarm with the updated time + scheduleTimer(); + } + } + + drawTime(); +} + +function handleTouch(x, y) { + const centerY = g.getHeight() / 2; + + if (y < centerY - 40) { + // Increase button area + adjustTime(60); + } else if (y > centerY + 40) { + // Decrease button area + adjustTime(-60); + } else { + // Center area + if (!timerRunning) { + startTimer(); + } + } +} + +// Function to update the display every second +function updateDisplay() { + if (timerRunning) { + let alarm = require("sched").getAlarm("ateatimer"); + timeRemaining = Math.floor(require("sched").getTimeToAlarm(alarm) / 1000); + drawTime(); + if (timeRemaining <= 0) { + timeRemaining = 0; + clearInterval(updateDisplay); + timerRunning = false; + } + } +} + +// Handle physical button press for resetting timer +setWatch(() => { + if (timerRunning) { + resetTimer(); + } else { + startTimer(); + } +}, BTN1, { repeat: true, edge: "falling" }); + +// Handle touch +Bangle.on("touch", (zone, xy) => { + handleTouch(xy.x, xy.y, false); +}); + +let isRunning = require("sched").getAlarm("ateatimer"); +if (isRunning) { + timerRunning = true; + // Start the timer to update the display + setInterval(updateDisplay, 1000); +} else { + // Draw the initial timer display + drawTime(); +} \ No newline at end of file diff --git a/apps/ateatimer/app.json b/apps/ateatimer/app.json new file mode 100644 index 000000000..7304a3d42 --- /dev/null +++ b/apps/ateatimer/app.json @@ -0,0 +1 @@ +{ "duration": 240 } \ No newline at end of file diff --git a/apps/ateatimer/app.png b/apps/ateatimer/app.png new file mode 100644 index 000000000..4c25f7d33 Binary files /dev/null and b/apps/ateatimer/app.png differ diff --git a/apps/ateatimer/metadata.json b/apps/ateatimer/metadata.json new file mode 100644 index 000000000..c4b8a1458 --- /dev/null +++ b/apps/ateatimer/metadata.json @@ -0,0 +1,14 @@ +{ "id": "ateatimer", + "name": "A Tea Timer", + "shortName":"A Tea Timer", + "icon": "app.png", + "version":"0.02", + "description": "Simple app for setting timers for tea. Touch up and down to change time, and time or button to start counting. When timer is running, button will stop timer and reset counter to last used value.", + "tags": "timer", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"ateatimer.app.js","url":"app.js"}, + {"name":"ateatimer.img","url":"app-icon.js","evaluate":true} + ], + "dependencies": {"scheduler":"type"} +} diff --git a/apps/backswipe/ChangeLog b/apps/backswipe/ChangeLog index 4e81269fe..c67453a09 100644 --- a/apps/backswipe/ChangeLog +++ b/apps/backswipe/ChangeLog @@ -1,6 +1,5 @@ 0.01: New App! 0.02: Don't fire if the app uses swipes already. 0.03: Only count defined handlers in the handler array. -0.04: Fix messages auto opened by `messagegui` could not be blacklisted. Needs - a refresh by deselecting and reselecting the "Messages" app throught Back Swipe - settings. +0.04: Fix messages auto opened by `messagegui` could not be blacklisted. Needs a refresh by deselecting and reselecting the "Messages" app throught Back Swipe settings. +0.05: React on swipes before the active app (for the most part) by using `prependListener`. diff --git a/apps/backswipe/boot.js b/apps/backswipe/boot.js index 8ff277634..cbc0f2563 100644 --- a/apps/backswipe/boot.js +++ b/apps/backswipe/boot.js @@ -38,6 +38,7 @@ // if we're in an app that has a back button, run the callback for it if (global.BACK && countHandlers("swipe")<=settings.standardNumSwipeHandlers && countHandlers("drag")<=settings.standardNumDragHandlers) { global.BACK(); + E.stopEventPropagation(); } } } @@ -56,5 +57,5 @@ } // Listen to left to right swipe - Bangle.on("swipe", goBack); + Bangle.prependListener("swipe", goBack); })(); diff --git a/apps/backswipe/metadata.json b/apps/backswipe/metadata.json index 4324286b5..78cd4dbe5 100644 --- a/apps/backswipe/metadata.json +++ b/apps/backswipe/metadata.json @@ -1,7 +1,7 @@ { "id": "backswipe", "name": "Back Swipe", "shortName":"BackSwipe", - "version":"0.04", + "version":"0.05", "description": "Service that allows you to use an app's back button using left to right swipe gesture", "icon": "app.png", "tags": "back,gesture,swipe", diff --git a/apps/clockcal/ChangeLog b/apps/clockcal/ChangeLog index 6780313ce..f2365fab7 100644 --- a/apps/clockcal/ChangeLog +++ b/apps/clockcal/ChangeLog @@ -8,3 +8,4 @@ 0.08: Fixed typo in settings.js for DRAGDOWN to make option work 0.09: You can now back out of the calendar using the button 0.10: Fix linter warnings +0.11: Added option to show prior weeks on clock calendar diff --git a/apps/clockcal/app.js b/apps/clockcal/app.js index 185f2adea..06436420a 100644 --- a/apps/clockcal/app.js +++ b/apps/clockcal/app.js @@ -2,7 +2,8 @@ Bangle.setUI("clock"); Bangle.loadWidgets(); var s = Object.assign({ - CAL_ROWS: 4, //number of calendar rows.(weeks) Shouldn't exceed 5 when using widgets. + CAL_ROWS: 4, //total number of calendar rows.(weeks) Shouldn't exceed 5 when using widgets. + CAL_ROWS_PRIOR: 0, //number of calendar rows.(weeks) that show above the current week BUZZ_ON_BT: true, //2x slow buzz on disconnect, 2x fast buzz on connect. Will be extra widget eventually MODE24: true, //24h mode vs 12h mode FIRSTDAY: 6, //First day of the week: mo, tu, we, th, fr, sa, su @@ -178,7 +179,7 @@ function drawWatch() { const dow = (s.FIRSTDAY + d.getDay()) % 7; //MO=0, SU=6 const today = d.getDate(); var rD = new Date(d.getTime()); - rD.setDate(rD.getDate() - dow); + rD.setDate(rD.getDate() - dow - s.CAL_ROWS_PRIOR * 7); var rDate = rD.getDate(); g.setFontAlign(1, 1); for (var y = 1; y <= s.CAL_ROWS; y++) { @@ -187,7 +188,7 @@ function drawWatch() { bottomrightY = y * CELL_H + CAL_Y; g.setFont("Vector", 16); var fg = ((s.REDSUN && rD.getDay() == 0) || (s.REDSAT && rD.getDay() == 6)) ? '#f00' : '#fff'; - if (y == 1 && today == rDate) { + if (y == s.CAL_ROWS_PRIOR + 1 && today == rDate) { g.setColor('#0f0'); g.fillRect(bottomrightX - CELL_W + 1, bottomrightY - CELL_H - 1, bottomrightX, bottomrightY - 2); g.setColor('#000'); diff --git a/apps/clockcal/metadata.json b/apps/clockcal/metadata.json index b84b08575..189d68597 100644 --- a/apps/clockcal/metadata.json +++ b/apps/clockcal/metadata.json @@ -1,7 +1,7 @@ { "id": "clockcal", "name": "Clock & Calendar", - "version": "0.10", + "version": "0.11", "description": "Clock with Calendar", "readme":"README.md", "icon": "app.png", diff --git a/apps/clockcal/settings.js b/apps/clockcal/settings.js index ddacb4a16..c3abe6f1c 100644 --- a/apps/clockcal/settings.js +++ b/apps/clockcal/settings.js @@ -1,7 +1,8 @@ (function (back) { var FILE = "clockcal.json"; const defaults={ - CAL_ROWS: 4, //number of calendar rows.(weeks) Shouldn't exceed 5 when using widgets. + CAL_ROWS: 4, //total number of calendar rows.(weeks) Shouldn't exceed 5 when using widgets. + CAL_ROWS_PRIOR: 0, //number of calendar rows.(weeks) that show above the current week BUZZ_ON_BT: true, //2x slow buzz on disconnect, 2x fast buzz on connect. Will be extra widget eventually MODE24: true, //24h mode vs 12h mode FIRSTDAY: 6, //First day of the week: mo, tu, we, th, fr, sa, su @@ -39,6 +40,14 @@ writeSettings(); } }, + '#Cal Rows Prior': { + value: settings.CAL_ROWS_PRIOR, + min: 0, max: 4, + onchange: v => { + settings.CAL_ROWS_PRIOR = v; + writeSettings(); + } + }, 'Clock mode': { value: settings.MODE24, format: v => v ? "24h" : "12h", diff --git a/apps/drained/app.js b/apps/drained/app.js index d4cb97db8..cefddbcc7 100644 --- a/apps/drained/app.js +++ b/apps/drained/app.js @@ -58,6 +58,7 @@ var draw = function () { }, 60000 - (date.getTime() % 60000)); }; var reload = function () { + var scroller; var showMenu = function () { var menu = { "Restore to full power": drainedRestore, @@ -69,9 +70,12 @@ var reload = function () { menu["Settings"] = function () { return load("setting.app.js"); }; menu["Recovery"] = function () { return Bangle.showRecoveryMenu(); }; menu["Exit menu"] = reload; + if (scroller) { + menu[""] = { selected: scroller.scroll }; + } if (nextDraw) clearTimeout(nextDraw); - E.showMenu(menu); + (scroller = E.showMenu(menu).scroller); }; Bangle.setUI({ mode: "custom", diff --git a/apps/drained/app.ts b/apps/drained/app.ts index fd39b11bd..bd79ebcab 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -78,8 +78,9 @@ const draw = () => { }; const reload = () => { + let scroller: MenuInstance["scroller"] | undefined; const showMenu = () => { - const menu: { [k: string]: () => void } = { + const menu: Menu = { "Restore to full power": drainedRestore, }; @@ -92,8 +93,12 @@ const reload = () => { menu["Recovery"] = () => Bangle.showRecoveryMenu(); menu["Exit menu"] = reload; + if(scroller){ + menu[""] = { selected: scroller.scroll }; + } + if(nextDraw) clearTimeout(nextDraw); - E.showMenu(menu); + ({ scroller } = E.showMenu(menu)); }; Bangle.setUI({ diff --git a/apps/dtlaunch/ChangeLog b/apps/dtlaunch/ChangeLog index 585e89ef9..aac1c30bd 100644 --- a/apps/dtlaunch/ChangeLog +++ b/apps/dtlaunch/ChangeLog @@ -31,3 +31,4 @@ when moving pages. Add caching for faster startups. 0.24: Add buzz-on-interaction setting 0.25: Minor code improvements 0.26: Bangle 2: Postpone loading icons that are not needed initially. +0.27: Bangle 2: Add setting to remember and present the last open page between instances of dtlaunch. diff --git a/apps/dtlaunch/README.md b/apps/dtlaunch/README.md index ff562d9db..276e62358 100644 --- a/apps/dtlaunch/README.md +++ b/apps/dtlaunch/README.md @@ -17,7 +17,9 @@ Bangle 2: ![shot3](https://user-images.githubusercontent.com/89286474/146471760-5497fd1b-8e82-4fd5-a4e3-4734701a7dbd.png) -## Controls- Bangle +## Controls + +### Bangle 1 **BTN1** - move backward through app icons on a page @@ -35,10 +37,28 @@ Bangle 2: **Touch Middle(1+2) area** - run the selected app -## Controls- Bangle 2 +### Bangle 2 **Touch** - icon to select, second touch launches app **Swipe Left/Up** - move to next page of app icons **Swipe Right/Down** - move to previous page of app icons + +## Settings + +**Show clocks** + +**Show launchers** + +### Only Bangle 2 + +**Direct launch** - launch on first touch. + +**Swipe Exit** - Swipe left to exit. + +**Time Out** - Return to clock after a short while. + +**Interaction buzz** + +**Remember Page** - Remember page when leaving and coming back to the launcher. diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js index 9da914980..ea163c57e 100644 --- a/apps/dtlaunch/app-b2.js +++ b/apps/dtlaunch/app-b2.js @@ -11,6 +11,7 @@ swipeExit: false, timeOut: "Off", interactionBuzz: false, + rememberPage: false, }, require('Storage').readJSON("dtlaunch.json", true) || {}); let s = require("Storage"); @@ -33,7 +34,17 @@ s.writeJSON("launch.cache.json", launchCache); } let apps = launchCache.apps; - for (let i = 0; i < 4; i++) { // Initially only load icons for the current page. + let page = 0; + let initPageAppZeroth = 0; + let initPageAppLast = 3; + if (settings.rememberPage) { + page = (global.dtlaunch&&global.dtlaunch.handlePagePersist()) ?? + (parseInt(s.read("dtlaunch.page")) ?? 0); + initPageAppZeroth = page*4; + initPageAppLast = Math.min(page*4+3, apps.length-1); + } + + for (let i = initPageAppZeroth; i <= initPageAppLast; i++) { // Initially only load icons for the current page. if (apps[i].icon) apps[i].icon = s.read(apps[i].icon); // should just be a link to a memory area } @@ -43,12 +54,11 @@ let maxPage = Npages-1; let selected = -1; //let oldselected = -1; - let page = 0; const XOFF = 24; const YOFF = 30; let drawIcon= function(p,n,selected) { - let x = (n%2)*72+XOFF; + let x = (n%2)*72+XOFF; let y = n>1?72+YOFF:YOFF; (selected?g.setColor(g.theme.fgH):g.setColor(g.theme.bg)).fillRect(x+11,y+3,x+60,y+52); g.clearRect(x+12,y+4,x+59,y+51); @@ -99,13 +109,32 @@ Bangle.drawWidgets(); // To immediately update widget field to follow current theme - remove leftovers if previous app set custom theme. Bangle.loadWidgets(); - drawPage(0); + drawPage(page); - for (let i = 4; i < apps.length; i++) { // Load the rest of the app icons that were not initially. + for (let i = 0; i < apps.length; i++) { // Load the rest of the app icons that were not initially. + if (i >= initPageAppZeroth && i <= initPageAppLast) continue; if (apps[i].icon) apps[i].icon = s.read(apps[i].icon); // should just be a link to a memory area } + if (!global.dtlaunch) { + global.dtlaunch = {}; + global.dtlaunch.handlePagePersist = function(page) { + // Function for persisting the active page when leaving dtlaunch. + if (page===undefined) {return this.page||0;} + + if (!this.killHandler) { // Only register kill listener once. + this.killHandler = () => { + s.write("dtlaunch.page", this.page.toString()); + }; + E.on("kill", this.killHandler); // This is intentionally left around after fastloading into other apps. I.e. not removed in uiRemove. + } + + this.page = page; + }; + global.dtlaunch.handlePagePersist(page); + } + let swipeListenerDt = function(dirLeftRight, dirUpDown){ updateTimeoutToClock(); selected = -1; @@ -142,6 +171,7 @@ drawIcon(page,selected,false); } else { buzzLong(); + global.dtlaunch.handlePagePersist(page); load(apps[page*4+i].src); } } @@ -162,7 +192,10 @@ back : Bangle.showClock, swipe : swipeListenerDt, touch : touchListenerDt, - remove : ()=>{if (timeoutToClock) clearTimeout(timeoutToClock);} + remove : ()=>{ + if (timeoutToClock) {clearTimeout(timeoutToClock);} + global.dtlaunch.handlePagePersist(page); + } }); // taken from Icon Launcher with minor alterations @@ -171,10 +204,9 @@ if (settings.timeOut!="Off"){ let time=parseInt(settings.timeOut); //the "s" will be trimmed by the parseInt if (timeoutToClock) clearTimeout(timeoutToClock); - timeoutToClock = setTimeout(Bangle.showClock,time*1000); + timeoutToClock = setTimeout(Bangle.showClock,time*1000); } }; updateTimeoutToClock(); } // end of app scope - diff --git a/apps/dtlaunch/metadata.json b/apps/dtlaunch/metadata.json index 0f6430829..1ff75b953 100644 --- a/apps/dtlaunch/metadata.json +++ b/apps/dtlaunch/metadata.json @@ -1,7 +1,7 @@ { "id": "dtlaunch", "name": "Desktop Launcher", - "version": "0.26", + "version": "0.27", "description": "Desktop style App Launcher with six (four for Bangle 2) apps per page - fast access if you have lots of apps installed.", "screenshots": [{"url":"shot1.png"},{"url":"shot2.png"},{"url":"shot3.png"}], "icon": "icon.png", diff --git a/apps/dtlaunch/settings-b2.js b/apps/dtlaunch/settings-b2.js index f6894e289..dcad03a65 100644 --- a/apps/dtlaunch/settings-b2.js +++ b/apps/dtlaunch/settings-b2.js @@ -8,6 +8,7 @@ swipeExit: false, timeOut: "Off", interactionBuzz: false, + rememberPage: false, }, require('Storage').readJSON(FILE, true) || {}); function writeSettings() { @@ -64,5 +65,12 @@ writeSettings(); } }, + /*LANG*/'Remember Page': { + value: settings.rememberPage, + onchange: v => { + settings.rememberPage = v; + writeSettings(); + } + }, }); }) diff --git a/apps/fwupdate/bootloader_espruino_2v25_banglejs2.hex b/apps/fwupdate/bootloader_espruino_2v25_banglejs2.hex new file mode 100644 index 000000000..7ee39eaf2 --- /dev/null +++ b/apps/fwupdate/bootloader_espruino_2v25_banglejs2.hex @@ -0,0 +1,1526 @@ +:02000002F0000C +:10700000F0FF032089730F00B1730F00B3730F00FB +:10701000B5730F00B7730F00B9730F0000000000C5 +:10702000000000000000000000000000FDC30F0091 +:10703000BD730F0000000000BF730F00C1730F008D +:10704000C3730F00C3730F00C3730F00C3730F002C +:10705000C3730F00C3730F00C3730F00C3730F001C +:10706000C3730F00C3730F00C3730F00C3730F000C +:10707000C3730F00C3730F00C3730F00C3730F00FC +:1070800011C40F00D1C10F00C3730F00C3730F00F1 +:10709000C3730F00C3730F006DC30F00C3730F00E2 +:1070A000C3730F00C3730F00C3730F00C3730F00CC +:1070B000C3730F00C3730F00000000000000000046 +:1070C000C3730F00C3730F00C3730F00C3730F00AC +:1070D000C3730F00C3730F00C3730F00C3730F009C +:1070E000C3730F00C3730F00C3730F0000000000D1 +:1070F00000000000C3730F0000000000C3730F0006 +:10710000000000000000000000000000000000007F +:10711000000000000000000000000000000000006F +:10712000000000000000000000000000000000005F +:10713000000000000000000000000000000000004F +:10714000000000000000000000000000000000003F +:10715000000000000000000000000000000000002F +:10716000000000000000000000000000000000001F +:10717000000000000000000000000000000000000F +:1071800000000000000000000000000000000000FF +:1071900000000000000000000000000000000000EF +:1071A00000000000000000000000000000000000DF +:1071B00000000000000000000000000000000000CF +:1071C00000000000000000000000000000000000BF +:1071D00000000000000000000000000000000000AF +:1071E000000000000000000000000000000000009F +:1071F000000000000000000000000000000000008F +:107200000348044B834202D0034B03B11847704735 +:10721000E0570020E0570020000000000548064B22 +:107220001B1AD90F01EBA301491002D0034B03B184 +:1072300018477047E0570020E0570020000000008A +:1072400010B5064C237843B9FFF7DAFF044B13B1AE +:107250000448AFF300800123237010BDF8570020CD +:1072600000000000B8CD0F0008B5054B1BB1054963 +:107270000548AFF30080BDE80840FFF7CFBF00BF6F +:1072800000000000FC570020B8CD0F00A3F5803AA5 +:10729000704700BF174B002B08BF134B9D46FFF7ED +:1072A000F5FF00218B460F461348144A121A00F0CE +:1072B00061F80E4B002B00D098470D4B002B00D0EF +:1072C00098470020002104000D000D48002802D03E +:1072D0000C48AFF3008000F029F82000290004F0EA +:1072E00053FC00F011F800BF00000800000000008F +:1072F00000000000F0FF0320F8570020707A002003 +:10730000000000000000000008B5064B044613B161 +:107310000021AFF30080044B1B6803B1984720465F +:1073200000F030F8000000001458002070B50D4D3A +:107330000D4C641BA4100026A64209D10B4D0C4C29 +:1073400005F00AFA641BA4100026A64205D170BD00 +:1073500055F8043B98470136EEE755F8043B98474B +:107360000136F2E7D8570020D8570020D857002020 +:10737000DC57002002440346934200D1704703F8D3 +:10738000011BF9E7FEE700BF0649074A074B9B1AB6 +:1073900003DD043BC858D050FBDC04F023FFFFF7AB +:1073A00079FF000054CE0F00B8570020F857002096 +:1073B000FEE7FEE7FEE7FEE7FEE7FEE7FEE7FEE7A5 +:1073C000FEE7FEE7012351B91F2886BF094A00F0F6 +:1073D0001F004FF0A0428340C2F80C3570471F28B1 +:1073E00086BF044A00F01F004FF0A0428340C2F85D +:1073F000083570470003005010B50446FFF7E2FF60 +:107400001F2C86BF04F01F04044B4FF0A04304F56B +:10741000E074032243F8242010BD00BF0003005095 +:1074200010B50B234B4303EBE003094C00F00700BE +:1074300001228240E05C0243E254064B1A688A4211 +:10744000C8BF1960044B1A688A42B8BF196010BDE2 +:10745000A8760020A4760020D457002030B507235A +:107460004FF0A0424FF080614FF00064C2F80C155D +:1074700000BF00BF00BF00BF40FA03F5ED074CBFDF +:10748000C2F80845C2F80C4500BF00BF00BF00BFEE +:10749000C2F8081500BF00BF00BF00BF013BE5D226 +:1074A00030BD00002DE9F84F284F294ED7F800A035 +:1074B000D6F80080C24547DC01210520FFF782FF96 +:1074C0000AFA01F202F10309224B0B22A9F102058B +:1074D00002FB0A3B9020FFF7C1FF2846FFF7BEFFE3 +:1074E0000024E11004F007001BF80110014111F025 +:1074F000010F0CBFFF2000200134FFF7AFFF582C15 +:10750000EFD101354D45E5D10AF1010AD04505F12C +:107510000209D9DA0020FFF7A1FFFFF79FFF01461C +:107520001B20FFF74FFF1A20FFF766FF0520FFF72C +:1075300049FF094B1978062081F001011970FFF706 +:1075400041FF00233C603360BDE8F88FA476002043 +:10755000D4570020A8760020A0760020BFF34F8FDC +:107560000549064BCA6802F4E0621343CB60BFF3DF +:107570004F8F00BFFDE700BF00ED00E00400FA05FB +:107580004FF0A043D3F810056FEA504000F001001F +:107590007047704708B5FFF7E1FF0000014B01227B +:1075A0001A707047C5740020024B800143F001033C +:1075B000184700BF90CD0F004FF0A0434FF400429A +:1075C00070B50144C3F80C254FF48036082400221E +:1075D000C3F80865D3F81055C3F80C65C5F34035FA +:1075E000013C45EA4202F3D100F8012B8142EDD182 +:1075F00070BDF0B501444FF0A0434FF400444FF488 +:10760000803510F8016B072246FA02F7FF074CBFDE +:10761000C3F80845C3F80C45013AC3F80855C3F848 +:107620000C55F1D28842ECD1F0BD38B54FF0A044F2 +:107630004FF48045C4F80C55FFF7DBFFC4F808553C +:1076400038BD37B54FF0A04405234FF480458DF881 +:1076500007300DF10700C4F80C550121FFF7C9FFF1 +:107660000DF107000121FFF7A7FFC4F808559DF8A9 +:10767000070003B030BD07B5AB230DF107000121B2 +:107680008DF80730FFF7D1FF322003B05DF804EB2F +:10769000FFF78ABFF7B501210E20FFF7ADFE0F20DF +:1076A000FFF7AAFE1020FFF7A7FE4FF0A0430C2221 +:1076B000C3F834276420FFF777FF6623012101A870 +:1076C0008DF80430FFF7B1FF9923012101A88DF84F +:1076D0000430FFF7AAFF3220FFF766FFFFF7CBFF6A +:1076E000FFF7C9FFFFF7C7FFFFF7C5FF0424062612 +:1076F00001274FF47A75FFF7A4FF83070AD401210D +:1077000001A88DF80460FFF790FF0A20FFF74CFFF7 +:10771000013DF0D10A20FFF747FF022101A8ADF893 +:107720000470FFF782FF0A20FFF73EFF013C05D1FE +:10773000054803B0BDE8F040FFF736BFFFF781FF13 +:1077400010F01C0FD5D1F3E7A0860100F7B5032395 +:107750008DF804304FF0A0460B0C49BAADF8061076 +:107760004FF48047042115468DF805300446C6F8CD +:107770000C750DEB0100FFF73CFF29462046FFF793 +:107780001BFFC6F8087503B0F0BD38B50D462022C2 +:10779000014604462846FFF7D9FF2B685A1C09D03A +:1077A00023F07F4320341819B0F1C14F8CBF002063 +:1077B000012038BD0020FCE70000000000000000B0 +:1077C000C3F10803DB0070B501330446002003A5B4 +:1077D0005B1920C940CAAD1920C4184720C940CA46 +:1077E000754120C420C940CA754120C420C940CA7F +:1077F000754120C420C940CA754120C420C940CA6F +:10780000754120C420C940CA754120C420C940CA5E +:10781000754120C4404170BD000000000000000020 +:10782000C3F10803DB0070B50133002403A500BFDA +:107830005B1920C940CAAD1B20C0184720C940CAE7 +:10784000B54120C020C940CAB54120C020C940CAA6 +:10785000B54120C020C940CAB54120C020C940CA96 +:10786000B54120C020C940CAB54120C020C940CA86 +:10787000B54120C06441B4FA84F0400970BD00BF36 +:107880002DE9F041013B00249B0025462646274672 +:107890005FF0000C03E05FEA070CBCEB030CB7EBF6 +:1078A0000C0E52F80E8051F80CE0AEFB08E814EB19 +:1078B0000E0455EB080556F100061CF1040C9C451E +:1078C00001DCBC45EBDDC4512C46354600260437AF +:1078D0009F42DDDDB7EB430FDDDDC451BDE8F08134 +:1078E00021EAE17292000021FFF744BD10B50023A8 +:1078F0001A465CB2A14203DCB2FA82F0400910BD24 +:1079000050F8234001332243F3E74A11012350F892 +:10791000220001F01F018B40184070474B1E10B52C +:107920005BB2041D1A0603D45A1E54F8221061B12A +:1079300001335BB25BB103F18042013A50F822207F +:10794000B2FA82F2C2EB431010BD1346EAE71846C2 +:10795000FAE710B500235CB2A24200DC10BD51F87A +:10796000234040F823400133F5E710B5013A52B205 +:10797000130601D5002010BD50F8224051F82230E6 +:107980009C4205D802F1FF32F2D24FF0FF30F2E70D +:107990000120F0E700EB81010023884200D370470B +:1079A00051F8042D43EA52030B60D307F5E770B595 +:1079B0009DF910601D4633460446FFF701FF30B9BC +:1079C000324621462846FFF7D0FF012807D033462C +:1079D0002A4621462046BDE87040FFF721BF70BD12 +:1079E00070B59DF910601D4633460446FFF718FF39 +:1079F00038B133462A4621462046BDE87040FFF79D +:107A0000DFBE70BD2DE9F04FA5B01D4604ABCDE93A +:107A100002310190294610461746FFF77FFFC0EB61 +:107A2000851424B2002C2646B8BF04F11F06634219 +:107A300046F3471603F01F0304F01F09314658BFF1 +:107A4000C3F1000914A8FFF74BFFB9F1000F4FEA8B +:107A500086062DDD14AB00221E44C9F1200C13460E +:107A60009D421AD814AB03EB850300936F1E24AB21 +:107A70004FEA45084FEA8509012603EB8707002CEA +:107A800053DA24AB03EB8606019856F8881C2A4685 +:107A9000FFF75FFF25B0BDE8F08F57F8230000FA2D +:107AA00009F10A4346F8042B013320FA0CF2D7E718 +:107AB00014AB2A4639469819FFF74BFFD2E75AF81C +:107AC000883C53F8202024AB03EB80030CF1010C1D +:107AD00053F8403C0B44D31A34BF4FF0010B4FF026 +:107AE000000B9A425EF8882C42F8203018BF5946A5 +:107AF0004FFA8CF04045E2DB731A5E42294614A827 +:107B00005E41FFF747FF09F190036B44009853F87B +:107B1000402C57F8403C294643EAC273013C47F8E1 +:107B2000403C24B2FFF736FFA9E724AB4FF0000C2E +:107B300086F0010E614603EB860A03EB8E0ED7E753 +:107B400030B51C4691B0054693F900306846FFF702 +:107B500097FE0146D4F8B0302846984711B030BDA2 +:107B600013460A46FFF7ECBF70B5036813F0010631 +:107B70000546144605D013460A460146FFF720FE87 +:107B8000064621462846FFF705FF46B104F180422C +:107B9000013A55F8223043F0004345F8223070BDD9 +:107BA000F0B50F46A1B006461946384615461C46A4 +:107BB000FFF79CFE28B1304621B0BDE8F040FFF74A +:107BC0008FBE224639466846FFF7C3FE294608A8FD +:107BD000FFF7BFFE214610A8FFF782FE01232146D2 +:107BE00018A81093FFF77CFE224608A96846FFF705 +:107BF000BCFE30B9224610A93046FFF7AAFE21B0DC +:107C0000F0BD009BDA0709D421466846FFF7C2FEA3 +:107C10002246294610A8FFF7A7FFE5E7089BDB07E8 +:107C200007D4214608A8FFF7B5FE2246294618A822 +:107C3000F1E7002823461CDD08AA69466846FFF7DD +:107C4000EFFD21466846FFF7A5FE224618A910A8B9 +:107C5000FFF78BFE002805DA10A923462A460846BE +:107C6000FFF7AEFD10A9234618AA0846FFF7D8FD76 +:107C7000CEE76A4608A8FFF7D3FD214608A8FFF71C +:107C800089FE224610A918A8FFF76FFE002805DA22 +:107C900018A923462A460846FFF792FD18A923464D +:107CA00010AA0846FFF7BCFDBFE72DE9F04793F99E +:107CB000006092B0044689461046314615461F467C +:107CC000FFF714FE002840F091803A4649460AA882 +:107CD000FFF746FF3B460AAA214602A8FFF730FFFE +:107CE0000AA908463A46FFF73BFF3B462A46494663 +:107CF0004846FFF725FF07F104083A46294628467B +:107D0000FFF72EFF43462A46214620460096FFF7FE +:107D10004EFE43462A46294628460096FFF747FE70 +:107D200043462A46214628460096FFF759FE3B4621 +:107D30002A4621462046FFF703FF434622462146B6 +:107D400028460096FFF733FE434600962A46214612 +:107D50002046FFF72CFE2368DB074AD53346424610 +:107D600021462046FFF72CFD314682462046FFF78C +:107D700011FE06F18043013B54F8232042EACA7207 +:107D800044F823203A4621462846FFF7E9FE4346B9 +:107D900002AA294628460096FFF722FE434602AA79 +:107DA000294628460096FFF71BFE02A908464346CF +:107DB0002A460096FFF714FE3B4602AA21462046BB +:107DC000FFF7BEFE0AAA4346104621460096FFF77B +:107DD00007FE324629462046FFF7BBFD49462846A6 +:107DE000FFF7B7FD0AA94846FFF7B3FD12B0BDE89B +:107DF000F08731462046FFF7CDFDC3E72DE9F0417E +:107E000015468AB004460E461C22002103A8FFF73F +:107E1000B1FA2F1D95F9008003232A4631462046EA +:107E20000293FFF79DFE3B4602AA21462046CDF86D +:107E30000080FFF7D5FD2B46324621462046FFF74E +:107E40007FFECDF800803B4605F1840221462046A6 +:107E5000FFF7ADFD0AB0BDE8F081F0B591B00D4679 +:107E60001C220021064609A8FFF784FA01241C22DF +:107E7000002101A80894FFF77DFA294608AA11F904 +:107E8000047B00943B461046FFF79AFC394608A84D +:107E9000FFF744FD441E24B2012C06DC3A46694635 +:107EA0003046FFF756FD11B0F0BD694668462A46D8 +:107EB000FFF756FE214608A8FFF727FD28B12B46FD +:107EC000324669466846FFF73BFE013CE3E70000A7 +:107ED00000487047E8CB0F00F0B5082289B0FFF7E3 +:107EE00038FDCB6A03930B6B04934B6B05938B6B41 +:107EF0000693CB6B07930C4606460027134669464C +:107F00006A466846CDE901770097FFF759FC0823D8 +:107F100005466A4631463046FFF752FC236B039311 +:107F2000636B0493A36B0593E36B0544CDE90637BC +:107F30006A46082369466846FFF742FC0823054461 +:107F40006A4631463046FFF73BFC236A0093636A7A +:107F50000193A36A0293A36B0693E36B0793054413 +:107F600008236A4631463046CDE904770397FFF788 +:107F700027FC636A0093A36AA26B0193E36A0293EE +:107F80000492636BE26B0393CDE90523236A0793A5 +:107F9000054408236A4631463046FFF711FCE36A80 +:107FA0000093236B0193636B0293236A0693A36A86 +:107FB0000793054408236A4631463046CDE90477E5 +:107FC0000397FFF72DFC236B0093636B0193A36B67 +:107FD0000293E36B0393636A0693E36A07932D1A94 +:107FE00008236A4631463046CDE90477FFF718FC8E +:107FF000636B0093A36B0193E36B0293236A039378 +:10800000636A0493A36ACDE90537236B07932D1A9E +:1080100008236A4631463046FFF702FCA36B009303 +:10802000E36BCDE90137636A0393A36A0493E36AC0 +:10803000CDE90537636B07932D1A08236A4631464D +:108040003046FFF7EDFB2D1A0D4C0FD435B9082241 +:1080500031462046FFF789FC01280FD0082322462D +:1080600031463046FFF7DCFB2D1AEFE708232246A6 +:1080700031463046FFF7A4FB2D18F7D409B0F0BD08 +:10808000ECCB0F00F0B5154689B01C4607460E46EE +:108090001A4629466846FFF763FD23466A46394675 +:1080A0003846FFF74DFD23462A4669466846FFF7E6 +:1080B00047FD23466A4631463046FFF741FD09B089 +:1080C000F0BD2DE9F0478AB01446DDF848A05546CA +:1080D0001F4615F9046B0096804689462B460246DA +:1080E000214602A8FFF77CFC02A952460846FFF78A +:1080F00037FD534602AA41464046FFF721FD53464D +:1081000002AA21462046FFF71BFD2B464A46394668 +:1081100038460096FFF764FC5246394602A8FFF73E +:108120001FFD02A92B46424608460096FFF758FC61 +:1081300002A92B46224608460096FFF751FC2B4623 +:108140004246214620460096FFF74AFC5346224607 +:1081500049464846FFF7F4FC2B4602AA4146204612 +:108160000096FFF73DFC5346224639463846FFF756 +:10817000E7FC2B464A46394638460096FFF730FC66 +:10818000324602A92046FFF7E4FB0AB0BDE8F087BB +:10819000F8B50E46D11C48BF911D144641F3870126 +:1081A0000546671EFFF79CFB002042B2A24200F189 +:1081B000010000DBF8BDBB1A23F00301B25C03F041 +:1081C0000303DB009A406B5813436B50EDE700004C +:1081D0002DE9F04FC9B008AA01F1400514464B78CB +:1081E0000E781B0443EA0663CE7833438E7804315D +:1081F00043EA06238D4244F8043BF0D11024916BEE +:1082000016464FEAF14383EA714383EA9123716A88 +:10821000366852F8045F31440B444FEAB54181EAB5 +:10822000F51181EAD50101340B44402CD363E6D12A +:10823000D0E914E30093836D0193C36D0293036E41 +:108240000393436E0493836E0593C36E0693DDE937 +:10825000057ADDE9031CDDE901592B4B009E0793EC +:1082600074464FF00008079A08AB52F804BB53F865 +:10827000283007924FEAF12282EAB1129B4482EA47 +:1082800071625A4427EA010301EA0C0B83EA0B03EB +:108290001A44524486EA05034FEA743A06EA050B8B +:1082A0008AEAB40A23408AEAB45A83EA0B0308F143 +:1082B00001085344B8F1400F02EB090B1344A946DF +:1082C000BA4619D173440365009B23444365019B5F +:1082D00033448365029B2B44C365039B5B44036665 +:1082E000049B0B444366059B63448366069B3B44A7 +:1082F000C36649B0BDE8F08F674635468C462646D2 +:1083000059461C46AFE700BFE8CA0F000E490F4AA6 +:10831000034630B500240025C3E91445C3E916120D +:108320000B4C0C4A0C4DC3E918420C4AC3E91A52D3 +:108330000B4A1A6702F17452A2F523020020A2F63A +:10834000924298645A6730BD67E6096A85AE67BB9A +:1083500072F36E3C3AF54FA57F520E518C68059B27 +:10836000ABD9831FF8B504460D4608302AB9AE18BC +:108370000027B54205D10020F8BD0029F7D10E2015 +:10838000FAE7A36C15F8011BE2180133402B1172B8 +:10839000A364EED10146FFF71BFFD4E9143213F5B5 +:1083A000007342F10002C4E91432A764E1E74068B7 +:1083B0004B6898428CBF00200120704730B53AB11D +:1083C0001368DB430A4D0144884204D1D84330BDD1 +:1083D0004FF0FF33F6E710F8012B5340082213F05B +:1083E000010418BF2C46013A84EA5303F7D1EBE7A6 +:1083F0002083B8ED50E8022FC2EA224240E802236F +:10840000002BF7D1704737B550E8013F9DB2C489C2 +:1084100025448489A54228BF2D1B0489A54202BF9B +:10842000BFF32F8F002207E0C5EA030540E801549F +:10843000002CE9D14FF001028DF803200193019A3D +:108440000A609DF8031001F0FF0321B1006810FAE3 +:1084500082F003B030BD1846FBE737B550E8023F65 +:108460001FFAA3F5C488A54202BFBFF32F8F0022D5 +:108470000DE0C48925448489A54228BF2D1BC3EA89 +:10848000054540E80254002CE8D14FF001028DF878 +:1084900003200193019A0A609DF8031001F0FF0385 +:1084A00021B1006800EB124003B030BD1846FBE775 +:1084B000014B436000207047DCCA0F00084670473C +:1084C00000207047024B1868003818BF0120704721 +:1084D000F86F002029DF704728DF704770B5066805 +:1084E000B36886B004460D4673B114220021684675 +:1084F000FEF740FFA36805932379019533B1012B63 +:108500000ED0B3686846984706B070BD01238DF859 +:10851000003023690293E368039363690493F0E7EF +:1085200002238DF80030E3681B030293F5E7000097 +:108530000D4B10B5012143600C4B53E8002F42EA6C +:10854000010043E8000494F0000FF6D14AB908494D +:1085500009781974074B08499A60C3E90012074A61 +:10856000DA60002010BD00BFDCCA0F00E46F0020FD +:10857000ED6D0020D06F0020F06D0020DC011C00AC +:108580000846704700207047024B187A003818BF21 +:1085900001207047E46F0020034B187A0122B0FAE3 +:1085A00080F05A7440097047E46F0020436843B17B +:1085B000026891680B4443605268934204BF0023F1 +:1085C000436070474FF08053D3F83021082A03BF2F +:1085D000D3F83401B0FA80F0400900207047000061 +:1085E0000A4B0222C3F80425BFF36F8FBFF34F8FEE +:1085F000C3F80805D3F80024002AFBD00022C3F8F2 +:108600000425BFF36F8FBFF34F8F704700E0014029 +:108610000F4B30B50124C3F80445BFF36F8FBFF390 +:108620004F8F01EB8202401A914207D10022C3F81A +:108630000425BFF36F8FBFF34F8F30BD441851F83F +:10864000045B2560D3F80044002CFBD0ECE700BFAE +:1086500000E0014010DF704711DF704713B50C4B8D +:108660000C4A00930C4B934208BF0023044601932D +:10867000019808B902B010BDD0E9003120469847F2 +:1086800018B16846FFF792FFF2E71120F2E700BF4A +:10869000D0CA0F0044CE0F003CCE0F0013B50A4BDA +:1086A0000A4A00930A4B934208BF002304460193F1 +:1086B000019B0BB902B010BD2046D3E900219047C1 +:1086C0006846FFF773FFF3E7C4CA0F002CCE0F0014 +:1086D00024CE0F0060DF704769DF704761DF7047AD +:1086E00070B5104A104C114EC6B0944208BF002419 +:1086F0004FF486750DF1020103A8ADF80250FFF7A3 +:10870000EDFF60B9CDE90164029B002BF2D003A814 +:10871000D3E90021904701A8FFF748FFF4E746B0EE +:1087200070BD00BF24CE0F001CCE0F00A8CA0F00E2 +:10873000024B1B780BB1FFF7D3BF7047DF6D0020F2 +:108740004BDF704730B50D4A0D4C0E4D85B094424D +:1087500008BF002401A8FFF7F3FF60B9CDE9025478 +:10876000039B002BF6D00198D3E90021904702A883 +:10877000FFF71CFFF4E705B030BD00BF4CCE0F0083 +:1087800044CE0F009CCA0F00013A024401398242D4 +:1087900000D2704711F8013F02F80139F7E70023D2 +:1087A000C0E90232C0E900118B781A44026191F9E4 +:1087B00003301A4442610878003818BF012070471E +:1087C00010B542681178034641B102F10C014160D5 +:1087D000117B29B9C2680168FFF7E1FF002010BDD5 +:1087E0005078117900F03004302C1BD1547B04F008 +:1087F0003004302C1ED190781969091A19610021B2 +:10880000507810F0300F02BF986801309860907B6C +:10881000084419690144196192F90F201144596102 +:108820000120DCE700F0F004202C03D1507910FB8C +:1088300001F1E5E700F0C000802808BF0421DFE770 +:1088400043681A44426011B101399A4201D10120B2 +:10885000704713F8010B01F8010FF6E730B5044635 +:1088600085B01546A9B90268114B9A4211D0102D56 +:1088700006D82A4669462046FFF7F0FF05B030BD0E +:10888000102269462046FFF7E9FF0028F6D0103D88 +:10889000EDE7A368AB4201D20020EFE723682A4648 +:1088A000204698470028F7D0A3685B1BA360E5E744 +:1088B00041880F0010B5836804460BB9002010BD35 +:1088C0000368012298470028F8D0A368013BA36001 +:1088D000F5E72DE9F3410F460DF107018046FFF75B +:1088E000E9FF054620B90025284602B0BDE8F08121 +:1088F0009DF907309DF80740002B13DA04F07F0440 +:1089000007260DF107014046FFF7D4FF0028EAD003 +:108910009DF8072002F07F03B3401C43130606F1C5 +:10892000070601D43C60DFE7232EEAD1DBE72DE91F +:10893000F341002506460F46A8462C460DF10701D7 +:108940003046FFF7B7FFC0B19DF807C0A4F1200380 +:108950000CF07F02C4F1200102FA03F322FA01F1C4 +:108960000B43A2401CF0800F45EA020543EA0808C9 +:1089700004F1070404D1C7E9005802B0BDE8F08152 +:10898000462CDBD10020F8E713B50446052921D891 +:10899000DFE801F0030F1720201E012201A9204665 +:1089A000FFF75CFF18B19DF90430002BF5DB02B036 +:1089B00010BD08220021204602B0BDE81040FFF79C +:1089C0004DBF01A9FFF785FF0028F0D0019AF1E71C +:1089D0000422EFE70020EAE773B50D4601A904463B +:1089E000FFF777FF064618B90026304602B070BD83 +:1089F00094E80F0085E80F0001998A42F4D3A9603A +:108A0000A3685B1AA360F0E737B50D4669461446C4 +:108A1000FFF78DFF30B12B79082BDDE9001203D170 +:108A2000C4E9001203B030BD022B4FEAE1700FD051 +:108A3000042B03D0012B0FD00020F3E721600B465D +:108A40000246824208BF8B420CBF01200020E9E7AA +:108A50000BB22380DA17F4E74BB22370FAE737B58D +:108A60000D4669461446FFF762FFA8B12B79013B1A +:108A7000072B20D8DFE803F01A161F121F1F1F0450 +:108A8000DDE90032C4E90032DDE90001914208BFAE +:108A900098420CBF0120002003B030BD009B236032 +:108AA0000022F1E7009B23809BB2F9E7009B237033 +:108AB00003F0FF03F4E70020EEE773B50E466946C6 +:108AC0001546FFF734FFA8B1DDE900245308D207AB +:108AD000327943EAC47302F1FF324FEA540444BFCF +:108AE000DB43E443072A05D8DFE802F01814040A40 +:108AF00004040407002002B070BDC5E90034FAE7A1 +:108B00002B601A46D917A14208BF9A420CBF012018 +:108B10000020F0E71AB22A80D117F4E75AB22A707F +:108B2000FAE713B5144604220DEB0201FFF796FE97 +:108B300008B1019B236002B010BD13B5144669460D +:108B40000822FFF78BFE18B1DDE90023C4E90023FA +:108B500002B010BD73B50D4601A906461446FFF7D5 +:108B6000B8FEA8B1019AFF2A12D86B7803F0C003AF +:108B7000802B02F101010BD02B798B4208D32146C7 +:108B8000304601F8012B02B0BDE87040FFF766BE29 +:108B9000002002B070BD2DE9F3410F4601A98046C7 +:108BA0001646FFF796FEA0B1019C621C4FF000052F +:108BB00004D27B7803F0C003802B01D1284608E063 +:108BC0003B799342FAD3224631464046FFF746FEB0 +:108BD000355502B0BDE8F0816CDF70476DDF70473E +:108BE00072DF704773DF704774DF704775DF70475F +:108BF00076DF70477ADF70477CDF70477DDF704734 +:108C00007FDF704786DF70478FDF704790DF7047E8 +:108C1000A8DF7047AADF7047ADDF7047AEDF70474F +:108C2000B0DF7047B1DF7047B5DF704762DF704774 +:108C300066DF704713DF704770B518228CB00021D3 +:108C40000DEB0200FEF796FB2823089316231F4C1A +:108C5000ADF806300023CDF80E30CDF81230ADF867 +:108C60001630022309260622237023715923012579 +:108C7000A27063710322FE230DF10601A0198DF885 +:108C800018508DF82D500294ADF80C606570E270AC +:108C9000A371FFF7B3FFB8B9BDF8063026725A19B1 +:108CA000E271BDF80C200A4C134402A906AA204622 +:108CB000ADF80C30FFF794FF30B92078FFF794FF40 +:108CC00020782946FFF78EFF0CB070BDC06D0020E4 +:108CD000BC57002038B1054B0360054B43600123AE +:108CE0000372002070470E20704700BF558D0F00A3 +:108CF000F58C0F0069B10B78022B0CD1022804D03F +:108D0000032814BF08201120704703230B70002094 +:108D100070470E2070470820704743690BB1C06848 +:108D20001847704737B50546044804680093E4685F +:108D300013460A462946A04703B030BDE05700203D +:108D400018DF7047014B06201B6818476C70002025 +:108D500029DF704770B504460D4601B30B78012B2F +:108D600006D01ED9033B012B94BF0820112070BDF3 +:108D70000D4ED6F89C3190B1013312D1002218214A +:108D80000430FFF71BFB07222060214606F5CE705A +:108D9000FFF7DEFF0028EAD102232B70E7E70E2061 +:108DA000E5E70820E3E700BF00F00F004FF4405371 +:108DB000054A5968914203BF986800F6FF706FF347 +:108DC0000B004FF480507047DBE5B15108B5FFF759 +:108DD000EDFF044B9B69184400F6FF706FF30B0026 +:108DE00008BD00BFC87400205B689A68054B9A42B2 +:108DF00007D1D0E90123044901320A60034A013B4B +:108E000013607047D0C90F00B4690020B06900201A +:108E100041DF704700B10047704700000A4AD2F8AE +:108E200000347BB109480023D2F80815D940C9079E +:108E300048BF03F5C07103F1010348BF42F82100A8 +:108E4000072BF1D1704700BF000001403546526E3C +:108E5000024B1B780BB1FFF7E1BF70474069002060 +:108E600010B5064C014622681AB11046FFF79FFA6A +:108E700010B90A60216010BD1446F4E7C4680020F0 +:108E800038B50E4B1B780446ABB1A0B1037D93B14E +:108E9000D0E903309847A3685BB1227D02F0FF055B +:108EA0003AB16268134463602046FFF7D9FF284651 +:108EB00038BD002323750025F9E700BF1C70002092 +:108EC0002DE9F0430368D3F8042185B00546002A54 +:108ED00074D12B68D3F840216AB10026C3F84061F1 +:108EE000D3F84031754C0293029B23681BB1206874 +:108EF000FFF7C6FF26607248704E724C03A9FFF759 +:108F0000ACFA00287DD1DFF8BC816C4CD8F8003079 +:108F1000002B00F0CC805A6823685B68216861B13F +:108F20002168002900F0C0809A4280F0BD8023684B +:108F30001B7D13B12068FFF793FFD8F8007017B1BD +:108F40003B68C8F80030DFF88C917E68D9F80030B3 +:108F50004FF48032C3F80823C3F848230022C3F833 +:108F60004021D3F84021039226F07F46039AD3F89C +:108F70004025C3F84065D3F80435D31A23F07F4366 +:108F8000012B05D1504B4FF4046043F00103984787 +:108F9000D9F800204FF48033C2F84433D2F80435B6 +:108FA000F61A310226F07F4372D543F07F4313F562 +:108FB0007A7F6FDD3846FFF763FFA7E70022C3F82B +:108FC0000421D3F804313D4A0193019B13682BB16E +:108FD00013685B68126823F07F435360394B1C6849 +:108FE000002C3FF476AF6368B3F1807F04D2204653 +:108FF000FFF746FF2468F3E7636823F07F4363606D +:10900000F8E70378012B2DD0022B07D1002223682B +:10901000002B39D0196821601A75F8E7A3B94368A5 +:109020001A7D8AB901221A75436829685A68D1F8ED +:109030000415521A25498A4282BF5A6822F07F429B +:109040005A604068FFF70CFFBDF80C20BDF80E30E9 +:109050009A4202D11A48FFF7CDF903A91848FFF741 +:10906000FCF94EE7336842689A4204BF002333603C +:1090700023682146002BE7D09A4202D113680B6087 +:10908000E2E719461B68F5E7114B01221A70DBE78E +:10909000022B8FDD4FF48033C2F80433236813B9F9 +:1090A0002B6801221A60276005B0BDE8F0832368B1 +:1090B000002BF9D12B6801225A60F5E718700020C7 +:1090C00008700020C468002090CD0F0017FCFF003E +:1090D0001C700020C45700202DE9F041134D0646B6 +:1090E0001C462846124B6B600F469046FFF70EF960 +:1090F00080B9104B2B60B6B12FB923681F2B0BD84A +:1091000048F2145006E03A4631462846FFF72AF95D +:109110000028F2D0BDE8F081224641460348BDE870 +:10912000F04100F0D1BE48F21050F3E7906B002000 +:1091300048CA0F006E5246482DE9F04FC24EC34B4D +:1091400032689A42ADF5137D044640F0D2817368CF +:109150005A79202A40F0D0819B68DFF8FC9298472A +:109160007668BB4996F805A0A24528BFA2460546E9 +:1091700052460AA8FFF708FBB64C767921463246DC +:1091800062A8FFF701FBA11932463044FFF7FCFA51 +:10919000B5F9023095F9004013F11F0648BF03F1FD +:1091A0003E0646F3471606F1FF3B52AF2AAA0023BC +:1091B00042F82B3047F82B3092AA95F9018002EB48 +:1091C0008B02494642F8E03C72A84246FEF7E0FFB7 +:1091D000A300049372AB03EB84031846424609EBE9 +:1091E00008010593FEF7D4FF424662A93846FEF710 +:1091F000CFFF424662AB99185AA8FEF7C9FF214635 +:109200003846FEF773FB20B95AA8FEF76FFB80467D +:1092100030B148F2425840460DF5137DBDE8F08F5D +:1092200005F124033246394618460393FEF79DFBA9 +:109230000128EED1039832465AA9FEF796FB012881 +:10924000E7D112AF039A334622A8FEF7A9FC47F8EC +:109250002B80B5F9023013F11F0B48BF03F13E0B11 +:10926000DA1D48BF03F10E02D21052454FEA6B1BC4 +:1092700028BF52464FFA8BFA914651463846FEF7C0 +:109280002FFB0AA94A463846FEF782FFB5F90210BD +:10929000B1EBC90F4FEAC90315D25B1A07EB8B0B71 +:1092A0004FF0000CC3F120005F45C0F0C18003986F +:1092B00052463946FEF759FB012804D0039A53461B +:1092C0003846FEF7ADFA0DF5027A39465046334678 +:1092D00022AAFEF7D5FA51463846039A3346FEF7DE +:1092E00091FB5046334622AA52A9FEF7C9FA3346EB +:1092F0005146039A1AA8FEF785FB2246504672A9EA +:10930000FEF727FB049B05990AEB030B5846FEF773 +:1093100020FB05F1440319463AA89946FEF719FBCC +:10932000049B42A809EB0301FEF713FB2B1D5146DA +:109330003AAA22A800940593FEF752FB5B465246D8 +:1093400042A93AA80095FEF7BCFE22A9084623468A +:109350002A1DFEF725FC22AA594650462B46FEF749 +:1093600091FE0023CDE90639314672AB3846CDE98E +:10937000083AFEF7D3FA314681461AA8FEF7CEFA2C +:109380008145B8BF81461FFA89F909F1FF3A0FFA02 +:109390008AFA51463846FEF7B8FA514607461AA8E7 +:1093A000FEF7B3FA031E18BF0123381E18BF0120B1 +:1093B00040EA43000DF1180B0DF1A80A5BF82010EC +:1093C00022465046FEF7C5FA049B32A81944FEF720 +:1093D000C0FA214622A8FEF783FA01232293A9F1BD +:1093E00002090FFA89F9B9F1000F37DA22A9084604 +:1093F000059A2346FEF7D4FB2B4622AA32A95046F3 +:10940000FEF740FE039832465146FEF7AEFA0128B9 +:1094100004D0039A33465046FEF702FA013C64B288 +:1094200052AA23065CD5B8F1000F3FF4F4AEF0E683 +:109430005BF8041D21FA03F242EA0C02CBF800208B +:1094400001FA00FC30E700BF207000207052464D4A +:1094500008690020C8680020287000202B4622AA36 +:10946000D5F8A47032A95046B847494612A8FEF76D +:109470004CFA494607461AA8FEF747FA031E18BFDA +:109480000123381E18BF012040EA430006AB53F801 +:10949000201011B322463AA8FEF75BFA049B42A8BB +:1094A0001944FEF756FA01462B4622AA3AA8FEF7BF +:1094B000E9FD059B00943AAA51464AA8FEF790FAA6 +:1094C00032AB524642A93AA80095FEF7FAFD22A90E +:1094D0002B464AAA0846FEF733FB09F1FF3980E71D +:1094E0005AF8243052F824104B4048EA0308013C53 +:1094F00097E748F240588EE648F211588BE600BFD5 +:1095000030B40546044803681C690A46A446294647 +:10951000002330BC604700BFE057002070B5EFF378 +:10952000108672B60C4A9468012384B993600B4B81 +:109530000B4DD3F8801029401160C3F88050D3F848 +:10954000841051604FF0FF32C3F88420234603702B +:1095500006B962B670BD00BFE06D002000E100E01A +:10956000FC06FFBD10B5064B002253E8001F01EAC0 +:10957000020043E8000494F0000FF6D110BD00BFD4 +:10958000F86F002008B5FFF7EDFF002008BD0000D0 +:109590002DE9F0431D4687B0144B80460F46164612 +:1095A0004FF0010953E8004F44EA090243E8002163 +:1095B00091F0000FF6D1BCB9AA0831463846FFF742 +:1095C00027F8FFF7CFFFD8F808304BB10E9A8DF887 +:1095D0000090CDE90147CDE90365059268469847BB +:1095E000204607B0BDE8F0831124F9E7F86F0020AA +:1095F0002DE9F04115461F4686B0164B80460E46B3 +:10960000012253E8004F44EA020143E8001090F0C1 +:10961000000FF6D1E4B921468D4213D1FFF7A2FF26 +:10962000D8F8083053B102228DF800200022CDE98D +:109630000126CDE90325059768469847204606B0E0 +:10964000BDE8F08106EB0130FEF7CAFF0131E3E728 +:109650001124F3E7F86F0020F8B5094E094CA41B5C +:109660000746E40800250436A54200D1F8BD56F8A7 +:109670003530384698470028F8D10135F4E700BF67 +:10968000F4CD0F00FCCD0F00062810B5044602D122 +:109690000020FFF7E1FF044B1B681BB12046BDE82B +:1096A0001040184710BD00BF787000207FB5002320 +:1096B000CDF80B308DF80F300A4BADF806109B89B2 +:1096C000ADF8083001238DF80A300DF10603CDE91D +:1096D0000430054B02A91888FFF7A0FA07B05DF81F +:1096E00004FB00BFA06D0020BA57002010B504464F +:1096F00086B01122002101A8FDF73CFE2378082B3B +:109700000BD1364A364913880988013B9BB2138036 +:10971000D1B1CBB9032311802370627823788DF8FF +:1097200005306021012A8DF804108DF806200DD037 +:109730000B2A11D12B4B00211A788DF807201970B4 +:10974000042101A8FFF7B2FF06B010BD062B05D01B +:10975000082B29D0032B27D00321F2E7E1688DF8ED +:109760000710D4E90123080A8DF80800080C090E37 +:109770008DF80A10110A8DF80B208DF80C10110CC1 +:10978000120E8DF80E201A0A8DF80F308DF8102069 +:109790001A0C1B0E8DF80D108DF809008DF8112094 +:1097A0008DF812300F21CCE7D4E90123110A8DF88E +:1097B00007208DF80810110C120E8DF80A201A0AD5 +:1097C0008DF80B308DF80C201A0C1B0E8DF809103B +:1097D0008DF80D208DF80E300B21B2E7BE6D002004 +:1097E000BC6D002069700020914209D150E8012F22 +:1097F000C2EA024240E80123002BF7D10120704762 +:109800000020704710B5084B9A685AB150B9EFF371 +:10981000108172B6054A1C6814605C6854609860D8 +:1098200001B962B610BD00BFE06D002000E100E0AC +:1098300037B51C4D012300202B70FEF70FFF1128B8 +:1098400028D00020FEF72AFF0DF10700FFF766FE83 +:1098500015491648FEF7FEFE154B0446B0FA80F097 +:10986000400918709DF80700FFF7CCFF9CB911491B +:109870002C7091F8162313235209D340DB0706D42A +:109880000D4B9A6852B11A6842F480021A600120A6 +:10989000FEF704FF0024204603B030BD4FF48003E0 +:1098A0000B60F4E7EC6D002093750F00B4CA0F0055 +:1098B000ED6D002000E100E0E06D002037B5174DB0 +:1098C00001202870FEF7CAFE11281CD00220FEF7E6 +:1098D000E5FE0DF10700FFF721FEFEF7BDFE104B80 +:1098E000044600229DF807001A70FFF78BFF5CB951 +:1098F0000C4B2C709A6852B11A6822F480021A60DC +:109900000320FEF7CBFE0024204603B030BD064BFB +:109910004FF48002C3F88020F2E700BFEC6D002016 +:10992000ED6D0020E06D002000E100E038B5174942 +:109930000B68024613F0010025D01548824221D061 +:10994000144A10884FF6FF72904216D043F0040379 +:109950000B601321FFF74CF9A8B90F4DC82445F04F +:1099600001054FF47A40A847013CFAD10B4B1B7814 +:1099700053B1BDE83840FFF7A1BF094B1878FFF796 +:1099800033F9F3E7002038BD0820FCE7B46D002070 +:10999000F4CD0F00BA57002090CD0F00ED6D0020E0 +:1099A000BC57002038B52A4C237A002B4ED0022B0E +:1099B00009D1032833D0274B00221B68E2601A79B3 +:1099C00042B1012A25D0637C002B31D1BDE838405B +:1099D00000F050B8D3E905128D1A142D94BF521916 +:1099E00014329A619142EED102284FF0000308BF71 +:1099F00019462372174B18BF0D211868FEF76EFD2C +:109A0000154B1A885B889A42DDD11448FEF7F2FCA8 +:109A1000D9E71A6901321A615B699A42E3E7E368A0 +:109A20000133082B01D8E360CDE70023E360DBE7D7 +:109A30000B4B1B7853B10B4B1B781BB1BDE8384067 +:109A4000FFF73CBFBDE83840FFF7F2BE38BD00BFAE +:109A5000E46F0020E06F0020CC6F0020D06F00206A +:109A6000EC6D0020ED6D0020831E012B01D8FFF767 +:109A700099BF704738B5244C244D237A3BB924490B +:109A80002448FEF7EAFC286008B9606038BD02236C +:109A900023722B681A7992B1012A26D028680321F3 +:109AA000FEF71CFD002323726360194B1A885B8844 +:109AB0009A42EBD1BDE838401648FEF79BBCD3E98B +:109AC0000520121A142AD3E9031328BF142292087E +:109AD000012A014438BF01221844FEF7FBFC50B1B3 +:109AE0001128DBD101232372D0E7D3E90303184403 +:109AF000FEF7F2FCF3E7237C002BC7D1BDE838402A +:109B00000220FFF74FBF00BFE46F0020E06F00208E +:109B1000CC6F0020D06F002010B40A4B012253E814 +:109B2000001F41EA020043E8000494F0000FF6D160 +:109B300029B95B7B1BB95DF8044BFFF79BBF5DF850 +:109B4000044B7047E86F002000F0FD03012B08D1A3 +:109B5000044B00225A74421E504250411874FFF7C1 +:109B600089BF7047E46F002013B504460DF107006C +:109B7000FFF7D4FC074A9DF807001368591C1160D1 +:109B8000054AA41AE4091C7002B0BDE81040FFF7B2 +:109B900039BE00BFBC68002018580020FFF7E4BFA2 +:109BA00037B505460C460F4801A9FEF72CFCB0B1AD +:109BB00005704460BDF80620BDF804100948FFF7A1 +:109BC00013FE60B1084B93F9043001215A0903F0E8 +:109BD0001F03994002F14003044A42F8231003B0E6 +:109BE00030BD00BF08700020C457002000E100E035 +:109BF000084B99420DD8084B02611B68D3F8043515 +:109C00000B444360836803B1816001460020FFF785 +:109C1000C7BF704717FCFF00C457002008B5FDF709 +:109C2000AFFC0B4A60B910600A4B0B4AC3F8002620 +:109C3000BDE808400948002240F6CD41FFF7D8BFF3 +:109C4000136801330A2B1360EEDDFDF787FC00BFBC +:109C50009C760020000001403546526E847600203C +:109C6000F8B50E4641490B780546174613BB4FF031 +:109C70008043D3F81824D00337D53D4B3D4A1A60B2 +:109C80003D4C3E480022C3E901223D4ADA60637937 +:109C90003C4A42F823003C4800EBC3031B795BB30A +:109CA0003A4A3B4BD360002090603A4AD36001238C +:109CB00093600B7000242C7529460120FFF770FF7C +:109CC000002E51D04FF4004C21464FF4FA704FF45F +:109CD0007A720023E6FB0C0102F0C6FB3A4601460D +:109CE0002846BDE8F840FFF783BF01229A60D3F809 +:109CF0001824D203FBD5C0E72268C2F8083594F9CE +:109D00000430002B27DA244A03F00F0C62444FF092 +:109D1000E00C82F818C003F01F025B099B0003F1FE +:109D200060434FF0010C03F561430CFA02F2C3F8F3 +:109D300080211A60637900EBC30240F83340236846 +:109D400082F804C00222C3F84423C3F80423134B4F +:109D500083F800C0A4E703F1604202F561424FF0CE +:109D6000E00C82F800C3D6E7F8BD00BF9C69002074 +:109D70000870002044690020C4570020C18E0F00E5 +:109D80005800080004700020FC6F00207C70002048 +:109D9000158E0F0028690020FCEC00E01C700020EC +:109DA000042810B5044608D802280BD8094B1B68B4 +:109DB0007BB12046BDE810401847831F012BF5D822 +:109DC000FDF7CCFB044A054847F23051FFF748FF46 +:109DD000ECE710BD8076002095750F007C700020A8 +:109DE00070B5134DD5F80034EBB1D5F80445114BDF +:109DF000640904EB440449F63F46B4428CBF002298 +:109E000001221A70FFF70AF8B44203D9D5F80C35CD +:109E1000DB0704D5084A0948A108FFF721FF084BD2 +:109E20004FF480321A60074B01221A7070BD00BFD8 +:109E30000000014040690020518E0F002869002079 +:109E400000E100E0C474002008B54FF472720948C4 +:109E50000021FDF78FFA084A02231360074A1360B6 +:109E6000074B00221A60074B57221A60BDE80840D2 +:109E7000FDF718BBA8760020D0570020CC57002053 +:109E8000A4760020D457002008B500210520FDF756 +:109E9000B3FA01211A20FDF7AFFA1B20FDF7ACFA47 +:109EA0000720FDF7A9FA0620FDF7A6FA044B05489E +:109EB0000B439847FFF7C8FFBDE80840FFF7C4BF52 +:109EC00090CD0F0000C409002DE9F04113681F2B4D +:109ED00004460D4616465ED900295FD0876CC3192B +:109EE0008022372F00F108081A7207F1090040D8C4 +:109EF000C7F1370200212044FDF73CFAD4E91423CE +:109F00000821E7FB0123C4E9142312BA626423FA8F +:109F100001F284F8433084F842201A0C1B0E84F8B6 +:109F20004030414684F841204046FEF751F9691E11 +:109F30000023626FDA4001F8012F226FDA400A71C4 +:109F4000E26EDA400A72A26EDA400A73626EDA409A +:109F50000A74226EDA400A75E26DDA400A76A26D62 +:109F6000DA400833202B0A77E3D133600020BDE8C4 +:109F7000F0817B1C402BC7F13F024FF0000188BFEE +:109F800000222044FDF7F6F941464046FEF720F94D +:109F900038220021B0E748F21450E8E70E20E6E747 +:109FA00007B5142200211148FDF7E4F9104B53E8DE +:109FB000021FD888B1EB314F4FF0000217BF89B2B2 +:109FC00040EA004041EA004004E05968B1EB314FFB +:109FD00008BF012243E802010029E8D18DF80720DB +:109FE0009DF80730002003B05DF804FBE46F00200B +:109FF000D06F00202DE9F34180460F46114801A99A +:10A0000016461D46FEF7FFF90446C0B1182200218E +:10A010000430FDF7AFF9089BBDF80620BDF8041029 +:10A02000A360C4E903670748C4F800806561FFF7CF +:10A03000DBFBFFF771FD002002B0BDE8F0810420DA +:10A04000FAE700BFD06F00202DE9F34180460D46AE +:10A05000114801A916461F46FEF7D5F90446C8B1B6 +:10A06000172200210530FDF785F92D0B0123BDF8DE +:10A070000620BDF8041023710748C4F80080A760CB +:10A08000E5606661FFF7B0FBFFF746FD002002B018 +:10A09000BDE8F0810420FAE7D06F0020034A0023D6 +:10A0A000C0E9003383601363704700BFC8740020A9 +:10A0B0002DE9F04FDFF8F880DFF8F89085B0461E04 +:10A0C00016F8013F13B905B0BDE8F08F2E2BD8F874 +:10A0D0000040D9F8005053D02B2B53D0602B01D91E +:10A0E000203BDBB2303B5E2B2CD8052293FBF2F2F7 +:10A0F00002EB82029A1A294F9B1A07EB43076B1D4A +:10A100000193631C0293A31C02EB420B29460393A9 +:10A1100037F8023B43FA0BFA1AF0040F02D020463C +:10A12000FDF77EF91AF0020F02D00298FDF778F9D8 +:10A130001AF0010F02D00398FDF772F9019B01316B +:10A140009942E5D133780A2B1ED1AB1D532BC9F8A8 +:10A150000030B5DD12494FF45C72A1F1580002F0F5 +:10A1600065F958220F480021FDF704F90E4B002233 +:10A170001A600E4B023D5722C9F800501A609FE743 +:10A180005C23AFE74023ADE70D2B0BBF0223043464 +:10A19000C8F80030C8F8004092E700BF28CD0F0093 +:10A1A00000770020187A0020A4760020D4570020E1 +:10A1B000D0570020CC5700201FB547F630020023AF +:10A1C000CDE901230DF10501CDF80B301C2220FA59 +:10A1D00002F303F00F042346092C94BF30333733C6 +:10A1E000043A01F8013F131DF1D101A8FFF760FF08 +:10A1F00004B010BD08B5FFF75BFF0348FFF758FF39 +:10A20000BDE80840FDF74EB970C70F0008B5072834 +:10A210001CD8DFE800F0041517191B131B130C489A +:10A220000C4BC3600022012340F6CD418360FFF751 +:10A23000DFFC0948BDE80840FFF7DCBF0748F9E745 +:10A240000748F7E70748F5E70748F3E708BD00BF09 +:10A25000847600201D9C0F0073C70F0087C70F0076 +:10A2600090C70F008DC70F001BC90F002DE9F04FDD +:10A27000ADF5157D10220146044608A8FDF766FAE3 +:10A28000089F7A1C4DD0099E002E4AD0B048FFF797 +:10A29000B1FF3846FFF790FFAE48FFF7ABFF3046FF +:10A2A000FFF78AFFAC48FFF7A5FFDDF828B0584656 +:10A2B000FFF782FFA948FFF79DFF0B98FFF77CFF90 +:10A2C000A748FFF797FFB7F5772F2AD2BB19B3F549 +:10A2D000772F019325D8A34804F1100AFFF78AFFCE +:10A2E000354653464FF00008002DCDF814801CDC95 +:10A2F000C34537D09C48FFF77DFF9C48FFF77AFFA6 +:10A300004046FFF759FF9A48FFF774FF9848FFF758 +:10A3100071FF0023974A984998485493549B93425D +:10A320001ADD0DF5157DBDE8F08FB5F5807FA946E6 +:10A3300028BF4FF4807919464A4614A80093FDF7C8 +:10A3400005FA05AA494614A8FEF738F8009B80468E +:10A350004B44A5EB0905C7E7C1F80006549B013340 +:10A360005493DBE78648FFF745FF8648FFF742FF37 +:10A370003D465146B346BBF5807FD94628BF4FF4D2 +:10A38000807954A84A460091FDF7E0F9009954A855 +:10A3900009EB050C2B7810F8012B93426DD07A480D +:10A3A00000930292FFF784FE2846FFF705FF7048EE +:10A3B000FFF720FF029A1046FFF7FEFE7348FFF7F3 +:10A3C00077FE009B1846FFF7F7FE6948FFF712FF7C +:10A3D00000256F48FFF70EFF062301210CA88DF81A +:10A3E00030301C3CFDF721F900230693069BB3F5A2 +:10A3F0007A7F4CDB02238DF830300021230C1C22A5 +:10A4000064BA0DA88DF83130ADF83240FCF7B2FFD8 +:10A4100020210CA8FDF709F9FDF713F9C307FBD4B8 +:10A42000002D40F08D805B48FFF7E4FE5A48FFF7AF +:10A43000E1FE72B6594CDFF844914F483346022290 +:10A440000021002B26DC3D465146B346BBF1000FF0 +:10A450003ADC5348FFF7CEFE002307AA31463846C0 +:10A460000793FDF7ABFF444B07904045C3F80096B8 +:10A4700061D04C48FFF7BEFEDFE70135654589D165 +:10A48000BBEB090B49447FF476AF0125A1E7069B9E +:10A490000133AAE7019DC4F80425ED1AD4F800C4DD +:10A4A000BCF1000FFAD0C4F80855D4F80054002DC0 +:10A4B000FBD0C4F80415D4F80054002DFBD0A3F54C +:10A4C0008053C0F80096BCE7BBF5807F5A4654A87D +:10A4D00028BF4FF48072CDE90212FDF737F9039AD5 +:10A4E000029954A82B4600904FF0010E5519C4F85C +:10A4F00004E5D4F800C4BCF1000FFAD0009850F87D +:10A5000004CB0090C3F800C0D4F800C4BCF1000F25 +:10A51000FAD00020C4F80405D4F800C4BCF1000F40 +:10A52000FAD004339D42E2D1134B1144ABEB020B42 +:10A53000C3F800968AE71248FFF75CFEFDF70EF8B5 +:10A5400019480DF5157DBDE8F04FFFF753BE00BF6C +:10A5500098C70F00A5C70F00ABC70F00B1C70F000A +:10A56000B6C70F00BFC70F00CBC70F00D8C70F007B +:10A5700072C70F003F4B4C00000001403546526E41 +:10A58000E5C70F00ECC70F00F7C70F0000C80F00AA +:10A5900004C80F0013C80F0027C80F0000E00140D7 +:10A5A00033C80F003DC80F004DC80F0008B5104656 +:10A5B0001A4601F03BFF002008BD08B510461A46B8 +:10A5C00001F034FF002008BD70B54268527802F0F7 +:10A5D0000F01082986B003461ED103691C680026B6 +:10A5E0000CB906B070BD23686568267399682A4661 +:10A5F0006846FEF7D4F804F10C0305934B780495F4 +:10A6000003F0C003802B08BF231D684608BF0493D6 +:10A61000FFF7DAFFA468E3E73F2A28D802F0300109 +:10A62000102911D14269002111705A6818695378B4 +:10A63000946803F00F03072B0CD10146204606B0A7 +:10A64000BDE8704000F01FB89106EED543690022C6 +:10A650001A70C6E71279214624B106B0BDE87040F1 +:10A6600001F0E4BE06B0BDE87040FCF783BE02F026 +:10A67000C0018029B5D1006900210160920644BF64 +:10A680005B691970ADE77FB50A4601466846FEF77B +:10A6900086F830B16846FFF797FF6846FEF790F8F6 +:10A6A000F7E707B05DF804FB2DE9F043D2F804C0EA +:10A6B0009CF8013013F0C00E89B006460C461546D2 +:10A6C00004D0BEF1400F6BD0002445E003F00F0230 +:10A6D000604903F03003202B51F8227023D007D8B3 +:10A6E000DBB92A6961463B4609B0BDE8F04318472B +:10A6F000302BE9D16B699CF800101970072A0AD138 +:10A700006B6828691A797146FCF734FE6B68296911 +:10A710009868FFF7B8FF2A693FE06B6901221A7059 +:10A720002A696968DFE7022CD5F8148027D1042A4A +:10A7300025D804A9FEF750F904460028C4D0069B8A +:10A740002BB1696898F800304A799A4208D8059B7D +:10A750007360069B002BB7D1204609B0BDE8F0839B +:10A7600008792A6900FB032204A8B84728B198F8A1 +:10A770000030013388F80030E1E70446E7E798F855 +:10A7800000309CF805209A429ED92A699CF8041052 +:10A79000581C88F8000001FB032269683046A2E7D4 +:10A7A000D2F81080474657F8043B23B909B0BDE8FA +:10A7B000F043FEF7E9B8022914D104A9FEF70CF919 +:10A7C000002881D0D8F8003069683A4604A8984734 +:10A7D000044600283FF478AF069B002BF2D1059B7E +:10A7E0007360B9E7012925D005292BD000297FF412 +:10A7F0006BAF0DF1040901340B2C3FF465AF01225E +:10A8000049463046FEF72AF800283FF45DAF19F9B3 +:10A81000013B002BEFDB104B049301ABCDE905347A +:10A8200000230793D8F8003069683A4604A898478F +:10A83000044691E7082201A9FEF710F80824002831 +:10A84000E9D141E704220DEB0201FEF707F80424E9 +:10A85000F5E700BF78CA0F0041880F002DE9F047E7 +:10A860008EB00446002702A8CDE90077FDF797FFD8 +:10A87000A3683BB108A92046FEF72BF840BBA368AC +:10A88000002B52D1DDE9033402A85D78FDF798FF73 +:10A890000028F7D115F0300F03D1039B1B7803B1CB +:10A8A0000134002C6CD0630969460022934261D1C7 +:10A8B0000EAA02EB830304F01F0453F8383CC4F1E2 +:10A8C00020044FF0FF30E040C31A584258412DE0B9 +:10A8D000089D002DD6D0039E4FEAD50805F0070548 +:10A8E000039B1A78904504D15B7803F00F02082A85 +:10A8F00064D102A8FDF764FF039B9E42F0D1474557 +:10A900000DD8039A537803F00F03082B3AD002A80E +:10A91000FDF756FF039B9E42F3D14FF0FF372946C8 +:10A920002046FEF731F80028A2D100200EB0BDE885 +:10A93000F08799680B7898453ED1D6F804A008A80E +:10A940005246FDF72CFF06F10C030D934B78CDF822 +:10A9500030A003F0C003802B04BF331D0C930123F0 +:10A96000337308AA29462046FFF79EFE22E0994548 +:10A97000D5D07DE751F8040B0130D6D1013295E7EF +:10A980000120D3E717784745C9D8069BD4F808902B +:10A990001E68A368002EEAD099457FF469AF33683A +:10A9A000D3F800A0BAF1000FC3D02B46424631467F +:10A9B0002046D0470028B8D0B668EAE713F0300F39 +:10A9C0000FD1049A3F2A0CD851090EAB03EB810139 +:10A9D00002F01F020123934051F8382C134341F831 +:10A9E000383CE66826B102AB2A4641462046B047CD +:10A9F00002AA29462046FFF757FE94E7F0B585B036 +:10AA00008F680E46694605461446FDF7E5FF88B196 +:10AA1000B06878B1737803F03003202B03D121465E +:10AA20003846FFF730FE224639466846FFF716FFE4 +:10AA3000019B6B6005B0F0BD70B50E4B0E4C9A6B70 +:10AA40000E4E0F4D0F4921605C33C4E901320E4BAD +:10AA50000E4AE360002313600D4A31462846136016 +:10AA6000FFF711FE324629462046BDE87040FFF749 +:10AA7000F5BE00BFC8740020A0690020086C00204B +:10AA8000ACC90F0041880F00E98D0F00B4690020A8 +:10AA9000B06900202DE9F3477C4ED6E90E329A4288 +:10AAA00040F0EE80DFF8208298F8003053B1FEF7D6 +:10AAB0008DF9774B726A1860764B1A60012002B0EC +:10AAC000BDE8F087FFF7B8FF28B1734B93F89C50AF +:10AAD0001DB91A780AB90520F1E7DFF8B491DFF85B +:10AAE000B4A10022C9F80020CAF800204DB16B4D76 +:10AAF00093F83871A5F199042023019325B9132007 +:10AB0000DDE7674C2F46F7E70FBB66496648674AA3 +:10AB10000968006801ABFEF7DFFAB0B92B78402B6B +:10AB200013D1634A6B1C413553F8041B42F8041BD4 +:10AB3000AB42F9D10198FEF7FFFA05460028CAD1C9 +:10AB400094F858302BB90F20B9E70A20B7E7162040 +:10AB5000B5E794F859100329F5D894F87130032B10 +:10AB600040F09080237B002BEDD02369342B40F004 +:10AB70008B804FF44052237D50684E4A904235D12D +:10AB800083B1A26972B14FF44052908904F114026A +:10AB900052F804CF84451BD00137FFB2BB42F7D136 +:10ABA00012208CE791B9012B12D9A26982B94FF416 +:10ABB000405204F1140097890A4650F804CFBC456E +:10ABC00006D00132D2B29342F7D1E9E70129E7D0AA +:10ABD00023799BB10129A36894BFB268F2689A42B5 +:10ABE0008CBF0023012393B9102068E713B1A36938 +:10ABF000002BD5D12379002BEAD1D1E70129A2D1AD +:10AC000088F8001094F85A3053B3E56D28E001231A +:10AC100088F8003011BB94F868300BB3E56E002D56 +:10AC200091D0CAF80050FEF7D1F8234C201A854283 +:10AC300007D9FEF7BBF8241AA5421DD81F48FFF715 +:10AC40002DFA002201231E48C6E90423FFF726FA45 +:10AC50007562FEF7BBF8C9F800002FE7C807D1D42A +:10AC60008907DCD594F86030002BD8D0154B626E84 +:10AC7000C3F57E239A4201D9042020E71544CEE78C +:10AC800008201CE714201AE7112018E7C8740020D8 +:10AC90007470002070700020086C0020416D00204E +:10ACA0000C6C0020B0690020B46900200869002005 +:10ACB000C8680020DBE5B15100400F00E0740020BF +:10ACC000EC74002000700F00687000202DE9F04740 +:10ACD000A64E3368DA0790B000F14681A44BA54A2E +:10ACE0001860A54B136020231168481C10600B707E +:10ACF000013BDBB2FF2BF7D10023CDE90A331371FF +:10AD000004930C9309A802230993FEF719F804464B +:10AD100040B99A48FDF78EFF044618B9984B1B7846 +:10AD200023B10824204610B0BDE8F087FEF780FD6F +:10AD300004460028F6D10125CDE90900914A0B907F +:10AD4000062309A920200492ADF828308DF824505C +:10AD50008DF82650FDF7C0FC4FF48173049A0B94D4 +:10AD600009A94020CDE90944ADF826308DF82550D9 +:10AD7000FDF7B2FC8323049A0B9409A92320CDE9A3 +:10AD80000944ADF826308DF82450FDF7A5FC049A4F +:10AD90000B9409A92846CDE909448DF82450FDF704 +:10ADA0009BFC4FF4B063049A099309A9A120CDE953 +:10ADB0000A44FDF791FC049A0B9409A9A020CDE95F +:10ADC0000944FDF789FC04A8FDF784FC044600282B +:10ADD000A8D16D4B024618216C481D70FDF7EEFAA4 +:10ADE0006B4AD2F89C31984212D16A4C02F5CE736C +:10ADF00002F5DA7218685968254603C5083393428C +:10AE00002C46F7D118682860336843F0020333609A +:10AE1000112309A88DF81030FDF7E0FE0446002844 +:10AE200080D19DF8253009A801338DF82530FDF734 +:10AE3000D3FE044600287FF475AF33689B074BBFF1 +:10AE4000544955498A69072248BF043192B204A87F +:10AE5000FDF7D2FE044600287FF464AF4F48FDF7AB +:10AE6000C9FE044600287FF45DAF4D4BDFF8388102 +:10AE70004FF6FF724FF001091A8002A94FF659638D +:10AE8000424648468DF80A90ADF80830FDF7C0FEFE +:10AE9000044600287FF446AF424808F10201FDF75E +:10AEA000C5FE044600287FF43DAF01461C2209A8D8 +:10AEB000FCF760FA9DF82430089443F004038DF801 +:10AEC00024300223ADF80C3098F802308DF80E30A3 +:10AED00003238DF806308023CDE90644ADF81C30FD +:10AEE00043464FF4885A33F8040BADF804A003AF7F +:10AEF00001AD04AA09A904970595FDF78BFE044648 +:10AF000000287FF40FAF01461C2209A8FCF732FA93 +:10AF100018238DF8243098F802308DF80E30132362 +:10AF20008DF806301723CDE90644ADF81C304346B2 +:10AF300004AA33F80C0B089409A9CDE90475ADF8FF +:10AF40000C90ADF804A0FDF765FE044600287FF4E0 +:10AF5000E9AEFDF771FE044600287FF4E3AE3368E6 +:10AF600043EA09033360DDE60024DBE6B46D00202C +:10AF7000B86D0020BC6800209868002000700F00A9 +:10AF8000ED6D0020B8570020DF6D0020A0F10F000C +:10AF900000F00F00846D00205DC80F0070CA0F0024 +:10AFA000BA57002060CA0F00A06D002070B5244B76 +:10AFB0004FF0FF324FF00051C3F88020C3F88021DA +:10AFC000C3F88420C3F884214FF4805388B00B6009 +:10AFD000EFF30580D3E90014002383F3148883F38F +:10AFE000108883F3118883F31388C0F3080028B90D +:10AFF00081F308889646204708B070BDCDE900333C +:10B00000CDE90233CDE904324FF080730793A1F10B +:10B01000200306946D461C4608AE2A4603CAB24277 +:10B0200020606160154604F10804F6D183F30888B6 +:10B030004FF0FF339E466FF006031847DCE700BF72 +:10B0400000E100E073B506460DF107000D46FEF77E +:10B0500065FA224B224A2348197800881478E3B213 +:10B06000844238BF0133C9B234BFDBB200239942F6 +:10B070002CD014781178CBB2884286BF0133DBB272 +:10B080000023E4B213709DF80700FEF7BBFB4FF6F8 +:10B09000FF739C421FD0144B1B6843F8345003EBE2 +:10B0A000C402B6B1114B1988114B1B68304604FB22 +:10B0B000013306F1180150F8044B43F8044B884261 +:10B0C000F9D118239380002002B070BD4FF6FF74B1 +:10B0D000D9E79680F7E70420F6E700BF98700020D4 +:10B0E0009970002094700020A070002096700020BD +:10B0F0009C70002070B50388232B8AB0044635D895 +:10B100000F2B04D8012B00F006810AB070BD103B54 +:10B11000132BFAD801A252F823F000BF9DB10F0003 +:10B12000BBB10F000BB10F00C1B20F0011B40F0083 +:10B130000BB10F000BB10F000BB10F000BB10F00E3 +:10B140000BB10F0023B40F000BB10F000BB10F00B8 +:10B150000BB10F000BB10F00E5B20F000BB10F00E8 +:10B16000EFB20F000BB10F00B1B20F00503B9AB21B +:10B17000062ACAD8062BC8D801A252F823F000BF6D +:10B18000E1B10F0027B30F0023B40F000BB10F0084 +:10B190000BB10F0077B20F00FFB20F00A54D8388EF +:10B1A0002B80A54B1B680BB101209847A349288829 +:10B1B0000AB0BDE87040FDF719BD9E4B4FF6FF7217 +:10B1C0001A809F4B1B68590701D4FDF735FD9A4B38 +:10B1D0001B68002B99D002200AB0BDE870401847C8 +:10B1E000984EE288B3889A428FD104A8FEF796F968 +:10B1F000954A964B1168994233D9481E106011F850 +:10B20000011C934D213305EBC1151B1A1179DBB2DB +:10B21000994200D213719DF81000FEF7F3FA002D49 +:10B220003FF473AF228A04F11201284601F0FEF8C0 +:10B230001822002104A8FCF79DF808238DF810308F +:10B24000844B0693844B0596CDE90735238AADF8E8 +:10B250002430824B1B88172B05D82846FEF784FC28 +:10B2600053E70025D7E77E4904A8FFF7EBFE002847 +:10B270003FF44BAFF1E7E188822917D8CB1E9A073C +:10B280000DD0CB1F9BB2013B5A4202F0030203F0E8 +:10B29000030301F1FF3158BF5342C91A89B2654B0C +:10B2A00018880AB0BDE87040FDF7BEBC8321F6E700 +:10B2B000002204A98088CDE90422FDF7A7FC24E739 +:10B2C0005C4C0223049304AA02AB2088059342F647 +:10B2D0000521FDF7A1FC002320881A468521FDF7F2 +:10B2E0008FFC12E7534B00F10801188860E7002338 +:10B2F00004A98088ADF81030FDF786FC05E7A37936 +:10B30000002B7FF402AF4B4B188813210AB0BDE825 +:10B310007040FDF76DBC474B188800210AB0BDE8AE +:10B320007040FDF785BCA379002B3FF4EEAE022BF5 +:10B330007FF4EBAE434D2189AA8991427FF4E5AEBB +:10B34000A27B012A7FF4E1AE4FF480320592228A7B +:10B35000384EADF81820628AADF81A2004F11402B4 +:10B36000049307920293298A308801AB02AA0393BF +:10B37000FDF752FC60B9BDF804303088DB0707D414 +:10B3800040F2FD1304A9ADF81430FDF749FCBCE60A +:10B39000002304A93088ADF81430FDF741FC0146C4 +:10B3A00000287FF4B2AE182204A8FBF7E3FF237D48 +:10B3B000284A8DF81030022B0595069221D0062BD5 +:10B3C0000FD0012B10D0069B002B3FF49EAE234BD9 +:10B3D0001B88172B7FF699AE214904A8FFF732FE90 +:10B3E00093E6637D0893EEE71E48FEF735F91E4BA2 +:10B3F0001A881E4B1A80637D0893D4F8163009937F +:10B40000E1E7194AB4F815301380184A1380DAE7D7 +:10B41000002380881A4619460AB0BDE87040FDF73F +:10B42000F1BB0023A0881A4619460AB0BDE8704057 +:10B43000FDF7F8BBBA570020B86D002070CA0F00A6 +:10B44000B46D0020A06D0020BC680020986800202A +:10B4500018580020ED960F009D9B0F00967000205D +:10B4600001B80F00F4CD0F00BC6D0020BE6D0020B0 +:10B4700038B5154D154904464FF4DC72284600F0E6 +:10B48000E3FF18B904B1A047002006E00F480121EE +:10B49000FEF736F8024608B1032038BD5821281DB2 +:10B4A000FCF78CFF4FF4DC7228602946084800F056 +:10B4B000BDFF0749054823464FF4DC72FDF732FC17 +:10B4C0000028E1D0E8E700BFC874002000F00F00BA +:10B4D000B869002081422DE9F74F04460F46154612 +:10B4E00004D10023184603B0BDE8F08F1F4B1B7832 +:10B4F0000E1A02F6FF78360B4FEA18380BB9FEF732 +:10B500006FFC082E28BF08263303DFF864B00193D0 +:10B51000002DE6D046452CBFC246B24651462046D5 +:10B5200034BFDDF80490A946FDF7EAFF0346002882 +:10B53000D8D109F1030222F0030239462046FDF773 +:10B54000F1FB03460028CDD1DBF830304B44CBF87B +:10B550003030FFF78DFFA8EB0A08A5EB09054C4436 +:10B560004F4403460028D3D0BCE700BFC47400207A +:10B57000C874002008B5104B996C01F50052506852 +:10B580000E4A904213D1D3E90C02904212D0121A03 +:10B5900002F6FF7201446FF30B0200F58050FFF7D3 +:10B5A00099FF034620B9BDE80840FFF761BF0323B8 +:10B5B000184608BD0023FBE7C8740020DBE5B15145 +:10B5C00030B5114B1148DA6A5C6A9D6CAC2A02BF37 +:10B5D0005B6BED18E41A85B02246294600F034FF73 +:10B5E00080B10B4BD3F800340BB1FDF717FC1022E0 +:10B5F00000216846FBF7BEFEA40868460195029448 +:10B60000FDF79EFB05B030BDC874002000700F0030 +:10B61000000001402DE9F047684D694C88B00746AD +:10B620000026641B1423B4FBF3F4A64211D11822A4 +:10B63000002102A8FBF79EFE0423624C8DF808301F +:10B64000614BD3F80090236D4B4517D001250024A2 +:10B650005DE02B6813B901361435E6E7DB6928464F +:10B6600098470028F7D0594B1B88172B59D95849B0 +:10B67000384608B0BDE8F047FFF7E4BC554BD3F8B7 +:10B680000080554B93F89C2003F10805A433002A51 +:10B6900018BF1D464FF0200A504ACDF804A001AB58 +:10B6A00049464046FDF718FD064620B117254C488F +:10B6B000FEF7F4FC13E04948524605F16F0100F033 +:10B6C000C3FE0028F2D195F855306BBB01222362EE +:10B6D0006B68E262A360A36CC4E909930125202290 +:10B6E00000214048FBF746FEF4223F48FF21FBF7CC +:10B6F00041FE0A2D4FF00003236388BF3B4BC4F883 +:10B70000488088BF0C223A4C84BF1A700B25D7E9B9 +:10B7100001138DF8095002A8984714B12046FFF78D +:10B72000A7FE08B0BDE8F08703F00201DB073FD5B4 +:10B7300008F50052DFF8C4C05068AB6D60453AD1DF +:10B7400003F5FF5C03F6FF73C3F30B030CF11F0C4F +:10B75000ACEB030C936863452DD34FF4405CDCF8ED +:10B760000430834213D19CF80030142B82BFDCF8E4 +:10B7700014302048B3FBF0F3107898BF002314284E +:10B7800082BF56691B4AB6FBF2F6B3420CD091B1A8 +:10B790001948FEF783FCAC23E362AB6D63630029B9 +:10B7A00099D06B68E36096E70029F4D1A523F3E70D +:10B7B000AA23E362F3E7052579E700BFE0570020FD +:10B7C000F4570020C874002070700020967000208C +:10B7D00015B60F0074700020086C0020706B0020FC +:10B7E000EC74002000750020247500206970002092 +:10B7F000458D0F0040420F00E0740020DBE5B151A1 +:10B800002DE9F041044686B0162200210DF1020018 +:10B81000FBF7B0FD25788DF8005001238DF801303D +:10B820000C2D00F2AA81DFE815F0660074001F00FD +:10B8300074007400A80174006B00740069000D00AE +:10B840002C006F004FF08053D3F800210192D3F801 +:10B8500004210292D3F80C2192020492D3F8102111 +:10B86000920203921B690593D4E901136846984735 +:10B870009DF80130012B00F074819B4B05201B6863 +:10B880006EE14FF44053994D58682A6A98498842AE +:10B890000CBF02230123012A227C08BF013352B9C5 +:10B8A00002238DF80430EB680293924B0393C3F5A7 +:10B8B0007E230493D8E7012A10D188420ED14FF499 +:10B8C00040531A78142A8CBF5B69002302934FF40B +:10B8D000805303934FF440539B68EAE79A4209D29E +:10B8E00001238DF80430AB680293FDF75FFAAB6972 +:10B8F0000390DEE7FF238DF80430B5E7237CFAE7F9 +:10B90000238AADF80430AFE7774B07201B689847D0 +:10B91000AAE7062D784B01D0012D01D122691A70BA +:10B920001E78012E04D0022E7CD000221A70C1E0B5 +:10B930006B1E072B98D801A252F823F05DB90F00B7 +:10B9400069B80F0019BA0F00E3B90F0069B80F000A +:10B9500013BA0F0069B80F0093B90F00624B0320B0 +:10B960001B689847676987B1B7F5807F0FD85F4E2E +:10B97000624B00211C2206F13C0019703163FBF779 +:10B98000F9FCB7638DF801506EE70325FAE704254B +:10B99000F8E7564DA78AE86BAB6B3A189A421ED867 +:10B9A000D4F810805C303A464146284400F03EFD11 +:10B9B000EB6B05F140023B4439464046EB63FCF734 +:10B9C000FDFC2864EB6B01932B6C0293E3688DF80C +:10B9D0000160002B3FF448AF2069984744E70326F5 +:10B9E000F0E7FFF757F80A2806D9454B0B381870CF +:10B9F0000B238DF8013037E701288DF801007FF423 +:10BA000033AF0020FFF734FD00283FF42DAF0A23A9 +:10BA1000EFE74FF480730393344BDA6B1B6C0192A6 +:10BA2000029321E7013D072D3FF61EAF01A353F816 +:10BA300025F000BF55BA0F0069B80F0031BB0F00E9 +:10BA40003DBB0F0069B80F0069BB0F0069B80F005C +:10BA5000B9BA0F00294B1B780BB90823C9E76269F3 +:10BA60000AB90323C5E7C2F30B0333B11F4B2549C2 +:10BA70005B6D096813448B42F3D1B2F5805F01D945 +:10BA80000423B6E7194B1F49586D096815188D42F4 +:10BA9000E3D85A64DA6C186518639A641A4B6169C2 +:10BAA0001B6801F6FF71090B1844FDF729FD0028FA +:10BAB0003FF4DAAE05239CE7104B1B78002BCCD06B +:10BAC0000A4DA28AD5E914315B1A696C13448B4282 +:10BAD000C7D80D4B2E6B1868D4E903313044FDF7FD +:10BAE00021F998B1E36877E76C700020C8740020F2 +:10BAF000DBE5B15100700F00B857002068700020DE +:10BB0000697000207070002074700020A28A2B6B76 +:10BB100013442B63A68A2B6D1E442E65A18A2069CF +:10BB200005F14802FCF74AFCCDE90160A8649BE6F8 +:10BB3000134B9A6C1B6D0292019395E6104BD3E95F +:10BB40001402596C821A8A4287D19A6C5865002176 +:10BB500020465964DA64FFF75DFD0A4B1B68042038 +:10BB6000984706B0BDE8F081054B9A6C1B6D0193B8 +:10BB70004FF480530292039376E6022339E700BF25 +:10BB8000C87400206C7000202DE9F04F4FF0A043E6 +:10BB90000C22C3F844278BB000211320FBF72CFCA8 +:10BBA0001D20FBF729FC1520FBF726FCFEF76CF99E +:10BBB000A948FEF71FFB4FF08043D3F8004414F070 +:10BBC0000B0F48D114F00F063CD0FBF7D9FC00282E +:10BBD00041D1002E3FD131460820FBF70DFC072054 +:10BBE000FBF70AFCFBF756FDB923012102A88DF8EB +:10BBF0000830FBF71AFD0220FBF7D6FC01211320C9 +:10BC0000FBF7FAFBFBF7BCFC01460028FAD1132036 +:10BC1000FBF7D8FB4FF0A043904AC3F84427D3F872 +:10BC2000442722F44032C3F84427D3F8442742F48F +:10BC30004032C3F844274FF080430122DA67C3F84B +:10BC40000025FEE74FF47A754FF47A70FBF7ACFCF1 +:10BC5000013DF9D1B9E7FEF717F9814D2B78002B9B +:10BC600075D14FF080434FF0FF327E48C3F8002477 +:10BC7000FEF7C0FAFBF784FC044668B97A48FEF781 +:10BC8000B9FAFBF707FD02A92046FBF77EFD002865 +:10BC900068D17648FEF7AEFA7548764FFBF784FC1C +:10BCA000754B764A1A600021754B3B603846FCF7AD +:10BCB000FFFB0546002840F0C980724C72494FF4E2 +:10BCC000DC72204600F0B2FB2668721C00F0B080E7 +:10BCD0002A465821201DFCF771FB864240F0A880BF +:10BCE000E36AAA2B00F0278100F29780012B00F075 +:10BCF000D980A52B00F01A81FBF742FC236A064687 +:10BD0000002B40F01B816148FEF774FA002E00F012 +:10BD100044815F48DFF88881FEF7CAF9FBF7C2FB70 +:10BD20004FF42066FBF72CFC002800F02C81002E3D +:10BD300000F0078140F2E730FBF736FC730604D1D0 +:10BD40004046FEF7B5F9FBF7ADFB013EEAE7E10738 +:10BD500002D52846FEF74EFA641015F8013B002B79 +:10BD6000FBD17BE74B4F4CF25236013E01D14A48A2 +:10BD700090E79DF80C302E2B2AD19DF80D30662BC4 +:10BD800026D19DF80E30692B22D19DF80F30722BF1 +:10BD90001ED19DF810306D2B1AD19DF81130772BE4 +:10BDA00016D19DF81230612B12D19DF81330722BF1 +:10BDB0000ED19DF81430652B0AD19DF815303BB992 +:10BDC0003648FEF717FA04F12000FEF74FFA63E752 +:10BDD000029D25F07F452335254425F00308A04525 +:10BDE000FFF457AF08F12003B3F1C14F3FF651AF55 +:10BDF00002A94046FBF7C9FC68B93D4005F58058EB +:10BE0000B8F1C14FBFF445AF02A94046FBF7BDFCF6 +:10BE100000283FF43EAF4446A7E7AC2B7FF46CAF5D +:10BE2000FFF7A8FB002840F08380FFF7C9FB7FE005 +:10BE300014484FF4DC720021FBF79CFA0123002028 +:10BE40006360FFF715FB00283FF44AAFFFF7AEF839 +:10BE500000200BB0BDE8F08F65C80F000C00030098 +:10BE600096CD0F0088C80F0091C80F009FC80F0023 +:10BE700020A10700E0570020807600200DA20F00CF +:10BE8000E8CC0F00C874002000F00F00C7C80F00F6 +:10BE9000D5C80F0000F0FFFFA9C80F00B8C80F00F9 +:10BEA00015C90F00FCF782FFD4F84880226B666A40 +:10BEB0000346984508EB0201104414BFB21A002251 +:10BEC000FFF708FB804660B9FCF770FF4246314639 +:10BED000FCF774FAA36A984203D10123C4E907036B +:10BEE000A6614FF000089448FEF7D8F8934B9448A9 +:10BEF00000221A70FFF7BCFA06460028A6D1B8F156 +:10BF0000000F11D0236A012B0ED1D4F81C80B8F198 +:10BF1000000F00F0C780FCF749FFA1693246FCF72B +:10BF20004DFA804500F0BE80FBF718FBFFF722FBBF +:10BF30004FF00108D7E7FFF743FBD2E700287FF473 +:10BF4000E8AE8048FEF756F97F48FBF72DFB7F4BA4 +:10BF500001214FF42032C3F80C15C3F80425D3F89F +:10BF600008250A43C3F80825794A1960C3F8002652 +:10BF7000D4F85C31D4F89C211340013340F0D280D6 +:10BF8000FFF714F862E7002EDBD0FDF75DFF714884 +:10BF9000FEF730F97048FEF72DF947F230516F4B3C +:10BFA0001B781BB90191FDF71BFF01996C4BDFF862 +:10BFB0001082DFF81092C8F800306A4A6A4EDFF843 +:10BFC00008A2DFF808B2694803F58473C9F80030A5 +:10BFD0000023137033701823AAF800302023ABF825 +:10BFE00000304FF08043D3F81C2512F0B10F1EBF74 +:10BFF000D3F81C2502F04E02C3F81C255C4AFDF75D +:10C000002FFE5C4B5C4A1A600020FDF73DFB5B4A4B +:10C010005B4B9B1ADB089D4247D15A4B5A483B6009 +:10C020000021FCF785FA054600287FF40FAFA36BCB +:10C03000002B46D10023554C554F2370554B012200 +:10C040001A70554ABF1AFF08BD4243D102221A7026 +:10C05000524D534900232B602022524B6B6005F157 +:10C060000800FCF791FB5049202205F12800FCF75D +:10C070008BFB4E4B2B602378002B34D14C4B4D4A1D +:10C080001A604D4B314C00221A70D4F800340BB1B9 +:10C09000FCF7C4FE334B32781B789A4228D1FCF768 +:10C0A000B7FEF2E742F2107179E752F835104148D5 +:10C0B0000193884700287FF4C9AE019B2F4A0135C0 +:10C0C000A9E7FEF7B9FC0028B4D0636A003B18BFAB +:10C0D0000123B0E752F8351088470028B8D12D4B1E +:10C0E0002D4A0135B0E7FEF7D5FC0128C6D0ADE6F4 +:10C0F0003378D8F80020BAF80050D9F8000002EBE5 +:10C10000C30103FB050052F8332089889047327839 +:10C11000BBF80010D3B2914286BF0133DBB20023DB +:10C120003370B7E74FF47F20FCF75AFA23495722C0 +:10C13000FCF76EFA24E700BFEC740020C574002001 +:10C140009D750F0023C90F00A0860100000001406B +:10C150003546526E88C80F0017C90F00C4740020FE +:10C16000A470002099700020987000207C7000203E +:10C1700095750F0078700020A19D0F00F4CD0F0081 +:10C18000FCCD0F0008CD0F00E057002068700020A4 +:10C19000F4CD0F001D700020F4CD0F0020700020A2 +:10C1A0009CCC0F00DCCC0F00BCCC0F007052464D75 +:10C1B0006C70002089960F0069700020C874002000 +:10C1C000A07000209C7000209670002094700020C9 +:10C1D000024B034A1B681068184700BF0470002018 +:10C1E000FC6F002008B54FF080430022C3F80C21FB +:10C1F000C3F81021C3F838254FF0805203F54043AF +:10C20000D2F80414C3F82015D2F80814C3F8241582 +:10C21000D2F80C14C3F82815D2F81014C3F82C1552 +:10C22000D2F81414C3F83015D2F81814C3F8341522 +:10C23000D2F81C14C3F84015D2F82014C3F84415E2 +:10C24000D2F82414C3F84815D2F82814C3F84C15B2 +:10C25000D2F82C14C3F85015D2F83014C3F8541582 +:10C26000D2F83414C3F86015D2F83814C3F8641542 +:10C27000D2F83C14C3F86815D2F84014C3F86C1512 +:10C28000D2F84424C3F87025FCF79CF918B12F4B61 +:10C290002F4AC3F88C26FCF795F918B12D4BFB22D9 +:10C2A000C3F81825FCF78EF958B14FF080424FF0D3 +:10C2B0008051D2F8E43ED1F8581261F30303C2F87A +:10C2C000E43EFCF77FF920B1234B4FF40072C3F832 +:10C2D00040264FF08043D3F80024D20744BF6FF0CC +:10C2E0000102C3F800241D4AD2F8883043F47003D9 +:10C2F000C2F88830BFF34F8FBFF36F8F4FF010231A +:10C30000D3F80C32DB071DD5154B0122C3F80425E9 +:10C31000D3F80024002AFBD04FF01022D2F80C32C0 +:10C3200023F00103C2F80C320D4BD3F80024002A8D +:10C33000FBD00022C3F80425D3F80024002AFBD048 +:10C34000FBF70CF9074B084A1A6008BD0050004083 +:10C350004881030000F000400090024000ED00E042 +:10C3600000E00140C05700200090D00307B50A4B01 +:10C370000A4A00930A4B934208BF00230193019B92 +:10C3800013B903B05DF804FBD3E900209047684679 +:10C39000FCF70CF9F3E700BFB8CA0F003CCE0F0062 +:10C3A0002CCE0F0070B58169124B134A11F8025C54 +:10C3B0000446D21A45B900690C21B2FBF1F2002102 +:10C3C0008A4204D1012010E04FF0FF30F4E71E68EC +:10C3D000AE420CD1461C02D05E68864207D19D68F1 +:10C3E000D4E90001D4E90223A847206070BD0131DF +:10C3F0000C33E5E710CE0F001CCE0F001EF0040F2B +:10C400000CBFEFF30880EFF30980FFF7CBBF00BF4D +:10C41000054B002282B0C3F80021D3F8003101930C +:10C42000019B02B0704700BF000001400A449142E6 +:10C4300000F1FF3300D1704710B511F8014B03F83C +:10C44000014F9142F9D110BD10B50139024490421B +:10C4500001D1002005E0037811F8014FA34201D07B +:10C46000181B10BD0130F2E753B94AB9002908BFC3 +:10C4700000281CBF4FF0FF314FF0FF3000F06AB9C9 +:10C48000ADF1080C6DE904CE00F006F8DDF804E02B +:10C49000DDE9022304B070472DE9F047089D0E4600 +:10C4A00004460F46002B4AD194468C45B2FA82F2DC +:10C4B00060D942B1C2F12003974020FA03F30CFA8D +:10C4C00002FC1F4394404FEA1C4E1FFA8CF6B7FB48 +:10C4D000FEF1230C0EFB117743EA074301FB06F044 +:10C4E00098420AD91CEB030301F1FF3780F0158154 +:10C4F000984240F21281023963441B1AA4B2B3FB82 +:10C50000FEF00EFB103344EA034400FB06F6A6429D +:10C510000AD91CEB040400F1FF3380F00081A6422D +:10C5200040F2FD806444023840EA0140A41B00212F +:10C530001DB1D4400023C5E90043BDE8F0878B421C +:10C5400005D90DB1C5E9000100210846F5E7B3FAA8 +:10C5500083F1002946D1B34202D3824200F2F58032 +:10C56000841A66EB030201201746002DE5D0C5E9C9 +:10C570000047E2E7002A40F09380A1EB0C034FEA6A +:10C580001C471FFA8CFE0121B3FBF7F607FB1630A0 +:10C59000230C43EA00430EFB06F0984208D91CEB3B +:10C5A000030306F1FF3802D2984200F2D0804646DB +:10C5B0001B1AA4B2B3FBF7F007FB103344EA0344A1 +:10C5C0000EFB00FEA64508D91CEB040400F1FF3366 +:10C5D00002D2A64500F2B6801846A4EB0E0440EA4B +:10C5E0000640A5E7C1F120078B4022FA07FC4CEA80 +:10C5F000030C06FA01FE20FA07F426FA07F344EAD0 +:10C600000E0400FA01F84FEA1C404FEA1449B3FB4C +:10C61000F0FE1FFA8CF600FB1E3349EA03430EFBC3 +:10C6200006F9994502FA01F20BD91CEB03030EF14E +:10C63000FF3A80F08580994540F28280AEF1020E8B +:10C640006344A3EB0909A4B2B9FBF0F300FB13990F +:10C6500044EA094403FB06F6A64208D91CEB04048D +:10C6600003F1FF3068D2A64266D9023B644443EA34 +:10C670000E40A41BA0FB02E6B4427346B14652D35F +:10C680004FD05DB1B8EB030264EB090404FA07F77D +:10C6900022FA01F31F43CC40C5E9007400214CE7A6 +:10C6A000C2F1200120FA01F30CFA02FC26FA01F192 +:10C6B000964033434FEA1C471FFA8CFEB1FBF7F05C +:10C6C00007FB1016190C41EA064100FB0EF68E42DC +:10C6D00004FA02F408D91CEB010100F1FF382DD255 +:10C6E0008E422BD902386144891B9BB2B1FBF7F60D +:10C6F00007FB161143EA014306FB0EF1994208D9E4 +:10C700001CEB030306F1FF3814D2994212D9023E02 +:10C7100063445B1A46EA004136E73946EDE61846BF +:10C7200002E7F045ADD2BEEB020366EB0C06013822 +:10C73000B146A6E74646ECE7034698E74046D3E70E +:10C74000D6467EE76444023847E708460DE7023ED6 +:10C7500063442DE7704700BFF8B500BFF8BC08BCC4 +:10C760009E467047F8B500BFF8BC08BC9E467047AF +:10C770000D0A000A484F4C442042544E20544F208A +:10C780005245424F4F54004552524F520044495374 +:10C79000434F4E4E45435400464C41534820484574 +:10C7A00041444552002041444452002053495A45D7 +:10C7B0000020435243002056455253494F4E0043F8 +:10C7C000524320544553542E2E2E00435243204DA5 +:10C7D00049534D41544348004E4F5420464C415319 +:10C7E00048494E4700435243204F4B005445535451 +:10C7F000494E472E2E2E00444946462041542000E3 +:10C800002056200052454D4F56452048454144454D +:10C81000522E004649524D57415245204449464602 +:10C820004552454E542E00464C415348494E472EE2 +:10C830002E2E0043524320434845434B004352436E +:10C84000204641494C212052455452590042494EFC +:10C85000415259204D4154434845532E004466757A +:10C8600054617267000A2020484F4C4420425554BE +:10C87000544F4E2032205345430D0A2020544F2060 +:10C880005455524E204F4E00424C20327632350ADB +:10C8900000434845434B2053544F52414745004EB7 +:10C8A0004F204E455720465700544F4F204D414E84 +:10C8B000592046494C455300464F554E4420464961 +:10C8C000524D574152450042414E4B3020494E5641 +:10C8D000414C49440052454C454153452042544E39 +:10C8E00020464F52204446550D0A484F4C442042A2 +:10C8F000544E20544F20424F4F540D0A0D0A3C20F5 +:10C900002020202020202020202020202020202027 +:10C9100020203E0D003D00444655205354415254C2 +:10C920004544000D0A424F4F54494E472E2E2E00CB +:10C93000010700009800000060C90F00020100001C +:10C94000010000000000000003050000410000009D +:10C9500000000000000000000000000000000000D7 +:10C96000011101FF0100000000000000021702FE9B +:10C9700094000000D0C90F0000000000000000007B +:10C9800000000000000000000101000001000000A4 +:10C99000000000000205000021000000000000006F +:10C9A000000000000000000000000000011704FC6F +:10C9B0009800000060C90F00021704FCDC000000B2 +:10C9C00030C90F000000000000000000000000005F +:10C9D000011104FC0400000000000000021104FC2E +:10C9E0000400000000000000032104FC041000000B +:10C9F00000000000041101FF010000000000000021 +:10CA0000051102FE0400000000000000061104FCF5 +:10CA10000400000000000000071104FC04000000F6 +:10CA200000000000081701FF2200000088C90F0065 +:10CA3000091001FF0100000084C90F000000000080 +:10CA400000000000000000000D830F0065830F0050 +:10CA5000C99E0F00200000007800000000000000C8 +:10CA600050EADA308883B89F604F15F30000C98E12 +:10CA70000600180000005802098A0F005F8A0F00A4 +:10CA8000BB8A0F00238B0F003B8B0F00558B0F00D1 +:10CA9000978B0F00FDA90F000000000044CE0F008F +:10CAA0004CCE0F00080000001CCE0F0024CE0F005B +:10CAB00008000000001002002CCE0F003CCE0F003A +:10CAC0000800000024CE0F002CCE0F00080000004C +:10CAD0003CCE0F0044CE0F00080000000010000004 +:10CAE0000400000001000000982F8A429144377131 +:10CAF000CFFBC0B5A5DBB5E95BC25639F111F159E1 +:10CB0000A4823F92D55E1CAB98AA07D8015B831222 +:10CB1000BE853124C37D0C55745DBE72FEB1DE80CE +:10CB2000A706DC9B74F19BC1C1699BE48647BEEFFD +:10CB3000C69DC10FCCA10C246F2CE92DAA84744A88 +:10CB4000DCA9B05CDA88F97652513E986DC631A8FE +:10CB5000C82703B0C77F59BFF30BE0C64791A7D5DD +:10CB60005163CA0667292914850AB72738211B2E65 +:10CB7000FC6D2C4D130D385354730A65BB0A6A764D +:10CB80002EC9C281852C7292A1E8BFA24B661AA859 +:10CB9000708B4BC2A3516CC719E892D1240699D669 +:10CBA00085350EF470A06A1016C1A419086C371EE2 +:10CBB0004C774827B5BCB034B30C1C394AAAD84EC0 +:10CBC0004FCA9C5BF36F2E68EE828F746F63A578FB +:10CBD0001478C8840802C78CFAFFBE90EB6C50A48E +:10CBE000F7A3F9BEF27871C608200001FFFFFFFF2E +:10CBF000FFFFFFFFFFFFFFFF00000000000000003D +:10CC00000000000001000000FFFFFFFF512563FC52 +:10CC1000C2CAB9F3849E17A7ADFAE6BCFFFFFFFFB7 +:10CC2000FFFFFFFF00000000FFFFFFFF96C298D844 +:10CC30004539A1F4A033EB2D817D0377F240A46345 +:10CC4000E5E6BCF847422CE1F2D1176BF551BF374E +:10CC50006840B6CBCE5E316B5733CE2B169E0F7C21 +:10CC60004AEBE78E9B7F1AFEE242E34F4B60D227EE +:10CC70003E3CCE3BF6B053CCB0061D65BC869876E4 +:10CC800055BDEBB3E7933AAAD835C65AAB7C0F0033 +:10CC90005B7E0F00FD7D0F00D97E0F004901B95268 +:10CCA000C5EF41DE27476A5527B31CE72D1ECB0F82 +:10CCB000A00C3792BE6AB2E99B2403956593690B79 +:10CCC0005EF09CFDA5C02CEEF1ECA5A1470A9B3FB0 +:10CCD000814C5FD407D8A31404C609D328004800A8 +:10CCE00000204000D17E0F00B1840F0085950F0019 +:10CCF000ADA50F0091950F00F1950F00BD840F00B9 +:10CD0000C1840F00C5840F0031850F00A19F0F0063 +:10CD1000BBA50F00F59F0F0049A00F0081850F00F4 +:10CD200085850F0089850F00D75D7552957C151399 +:10CD3000FF1DFF7F645ABF7EA91ABF7E4040922E1E +:10CD40000011922E6040823C554BF94D504B423DB4 +:10CD5000FE572559F57B255B3E577F594A798A79DD +:10CD60004A59775F9E656D5BAD6B2D5B15577B5B9D +:10CD7000545B527B5175D655ED076D049204150531 +:10CD8000D5270000000000000000000000000000A7 +:10CD90000338FDD8704750494E005741544348442A +:10CDA0004F47005357205245534554004C4F434B77 +:10CDB0005550004F464600001000000000000000E3 +:10CDC000017A5200027C0E011B0C0D0020000000B5 +:10CDD00018000000000000009A00000000410E0C46 +:10CDE00086018502840302470A41C6C5C4410B007F +:04CDF000000000003F +:08CDF400CDAC0F002D990F00DA +:10CDFC00BC68002098680020B968002018580020F2 +:04CE0C0080000000A2 +:0CCE10000000000003000000D58C0F00A3 +:08CE1C00F5B00F00000000005A +:08CE2400499B0F000000000013 +:10CE2C0045870F000000000031870F000000000054 +:08CE3C0099850F0000000000C1 +:08CE4400699A0F0000000000D4 +:08CE4C0040A4FF7F010000007B +:10CE54000100FFFFFF0000000090D003001001401C +:10CE6400110004000200000002000000570000004E +:08CE740069720F0041720F000A +:10CE7C0000000000000000001B8D0F0000100000DF +:04CE8C000000100092 +:020000020000FC +:020000041000EA +:0410140000700F0059 +:0410180000E00F00E5 +:04000003F00073890D +:00000001FF diff --git a/apps/fwupdate/custom.html b/apps/fwupdate/custom.html index 606e59d89..a604594b4 100644 --- a/apps/fwupdate/custom.html +++ b/apps/fwupdate/custom.html @@ -16,8 +16,9 @@ The DFU (bootloader) rarely changes, so it does not have to be the same version as your main firmware.

-

+ @@ -106,7 +108,8 @@ function onInit(device) { else if (crcs[0] == 3816337552) version = "2v21"; else if (crcs[0] == 3329616485) version = "2v22"; else if (crcs[0] == 1569433504) version = "2v23"; - else if (crcs[0] == 680675961) version = "2v24"; + else if (crcs[0] == 680675961) version = "2v24"; + else if (crcs[0] == 4148062987 || crcs[0] == 3675049818) version = "2v25"; else { // for other versions all 7 pages are used, check those var crc = crcs[1]; if (crc==1339551013) { version = "2v10.219"; ok = false; } @@ -127,7 +130,7 @@ function onInit(device) { } document.getElementById("boot-version").innerHTML = version; var versionNumber = parseFloat(version.replace(".","").replace("v",".")); - if (versionNumber>=2.20) + if (versionNumber>=2.25) document.getElementById("fw-old-bootloader-msg").style.display = "none"; }); } @@ -385,6 +388,7 @@ function createJS_bootloader(binary, startAddress, endAddress) { for (var i=startAddress;i { + settings.fix_req = v; + updateSettings(); + } } }; diff --git a/apps/gpssetup/gpssetup.js b/apps/gpssetup/gpssetup.js index f8fed68ff..b56bd50cf 100644 --- a/apps/gpssetup/gpssetup.js +++ b/apps/gpssetup/gpssetup.js @@ -1,5 +1,5 @@ const SETTINGS_FILE = "gpssetup.settings.json"; - +const BANGLE_VER = process.env.HWVERSION; //BangleJS2 support function log_debug(o) { //let timestamp = new Date().getTime(); //console.log(timestamp + " : " + o); @@ -106,49 +106,97 @@ function delay(ms) { function setupSuperE() { log_debug("setupGPS() Super-E"); - return Promise.resolve().then(function() { - UBX_CFG_RESET(); - return delay(100); - }).then(function() { - UBX_CFG_PMS(); - return delay(20); - }).then(function() { - UBX_CFG_SAVE(); - return delay(20); - }).then(function() { - log_debug("Powering GPS Off"); - /* - * must be part of the promise chain to ensure that - * setup does not return and powerOff before config functions - * have run - */ - return delay(20); - }); + switch(BANGLE_VER){ + case(1): { + return Promise.resolve().then(function() { + UBX_CFG_RESET(); + return delay(100); + }).then(function() { + UBX_CFG_PMS(); + return delay(20); + }).then(function() { + UBX_CFG_SAVE(); + return delay(20); + }).then(function() { + log_debug("Powering GPS Off"); + /* + * must be part of the promise chain to ensure that + * setup does not return and powerOff before config functions + * have run + */ + return delay(20); + }); + } + case(2):{ + //nothing more to do. + return; + } + } + } function setupPSMOO(settings) { log_debug("setupGPS() PSMOO"); - return Promise.resolve().then(function() { - UBX_CFG_RESET(); - return delay(100); - }).then(function() { - UBX_CFG_PM2(settings.update, settings.search); - return delay(20); - }).then(function() { - UBX_CFG_RXM(); - return delay(20); - }).then(function() { - UBX_CFG_SAVE(); - return delay(20); - }).then(function() { - log_debug("Powering GPS Off"); - /* - * must be part of the promise chain to ensure that - * setup does not return and powerOff before config functions - * have run - */ - return delay(20); - }); + switch(BANGLE_VER){ + case(1):{ + return Promise.resolve().then(function() { + UBX_CFG_RESET(); + return delay(100); + }).then(function() { + UBX_CFG_PM2(settings.update, settings.search); + return delay(20); + }).then(function() { + UBX_CFG_RXM(); + return delay(20); + }).then(function() { + UBX_CFG_SAVE(); + return delay(20); + }).then(function() { + log_debug("Powering GPS Off"); + /* + * must be part of the promise chain to ensure that + * setup does not return and powerOff before config functions + * have run + */ + return delay(20); + }); + } + case(2): { + var gpsTimeout = null; + var gpsActive = false; + var fix = 0; + function cb(f){ + if(parseInt(f.fix) === 1){ + fix++; + if(fix >= settings.fix_req){ + fix = 0; + turnOffGPS(); + } + } + } + function turnOffGPS() { + if (!gpsActive) return; + gpsActive = false; + clearTimeout(gpsTimeout); + Bangle.setGPSPower(0,settings.appName); + Bangle.removeListener('GPS', cb); // cleaning it up + gpsTimeout = setTimeout(() => { + turnOnGPS(); + }, settings.update * 1000); + } + function turnOnGPS(){ + if (gpsActive) return; + if(!Bangle.isGPSOn()) Bangle.setGPSPower(1,settings.appName); + Bangle.on('GPS',cb); + gpsActive = true; + gpsTimeout = setTimeout(() => { + turnOffGPS(); + }, settings.search * 1000); + } + turnOnGPS(); + break; + } + } } /** Set GPS power mode (assumes GPS on), returns a promise. @@ -161,16 +209,21 @@ require("gpssetup").setPowerMode({power_mode:"SuperE"}) // <-- Super E mode See the README for more information */ exports.setPowerMode = function(options) { - settings = require("Storage").readJSON(SETTINGS_FILE,1)||{}; + var settings = require("Storage").readJSON(SETTINGS_FILE,1)||{}; if (options) { if (options.update) settings.update = options.update; if (options.search) settings.search = options.search; + if (options.fix_req) settings.fix_req = options.fix_req; if (options.power_mode) settings.power_mode = options.power_mode; + if (options.appName) settings.appName = options.appName; } settings.update = settings.update||120; settings.search = settings.search||5; + settings.fix_req = settings.fix_req||1; //default to just one fix and will turn off settings.power_mode = settings.power_mode||"SuperE"; + settings.appName = settings.appName || "gpssetup"; if (options) require("Storage").write(SETTINGS_FILE, settings); + if(!Bangle.isGPSOn()) Bangle.setGPSPower(1,settings.appName); //always know its on - no point calling this otherwise!!! if (settings.power_mode === "PSMOO") { return setupPSMOO(settings); } else { diff --git a/apps/gpssetup/metadata.json b/apps/gpssetup/metadata.json index b8b6dfc23..ffe8d3fd8 100644 --- a/apps/gpssetup/metadata.json +++ b/apps/gpssetup/metadata.json @@ -2,11 +2,11 @@ "id": "gpssetup", "name": "GPS Setup", "shortName": "GPS Setup", - "version": "0.02", + "version": "0.03", "description": "Configure the GPS power options and store them in the GPS nvram", "icon": "gpssetup.png", "tags": "gps,tools,outdoors", - "supports": ["BANGLEJS"], + "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ {"name":"gpssetup","url":"gpssetup.js"}, diff --git a/apps/hasensors/ChangeLog b/apps/hasensors/ChangeLog index 7b3a63039..7372b1d12 100644 --- a/apps/hasensors/ChangeLog +++ b/apps/hasensors/ChangeLog @@ -1,3 +1,7 @@ 0.01: New app! 0.02: Add sensor icons Customize code directly, remove config file +0.03: Add HRM sensor + Add step count sensor + Add pressure and temperature sensors + Document Home Assistant `unique ID` workaround diff --git a/apps/hasensors/README.md b/apps/hasensors/README.md index e7f6ca98d..069122b6c 100644 --- a/apps/hasensors/README.md +++ b/apps/hasensors/README.md @@ -21,4 +21,30 @@ You need to fill out these fields: Currently creates these sensors: * `_battery_level`: Your watch battery level as percentage -* `_battery_state`: `charging` or `discharging` \ No newline at end of file +* `_battery_state`: `charging` or `discharging` +* `_hrm`: Heart rate (only if measured: this app doesn't enable/disable the sensor) +* `_steps`: Step Count +* `_pressure`: Pressure +* `_temperature`: Temperature + +## Home Assistant `unique ID` workaround + +If you try to customize the created entities, Home Assistant will complain that +> This entity ('sensor.…') does not have a unique ID, therefore its settings +> cannot be managed from the UI. + +The problem is that these sensors are created "dynamically", and there is no way +to supply a `unique ID`. +There is a workaround though: +1. Make note of the sensor name you want to customize (e.g. `banglejs_battery_state`). +2. Disconnect your Bangle.js from your phone, so it doesn't send updates. +3. Restart Home Assistant, the sensor is now gone. +4. Create a template sensor: choose "Template a sensor". + - Use the name from step 1 (without `sensor.` prefix). + - Set the state template to `unknown`. +5. Reconnect your Bangle.js: it will now update the new template sensor, which + *does* have a `unique ID`. + +**Warning:** Do not customize the `Entity ID`: the app sends values by sensor +ID, so you end up with both a non-updating template sensor and "dynamic" sensor +without `unique ID`. diff --git a/apps/hasensors/boot.js b/apps/hasensors/boot.js index efafbc8a3..feb7d246c 100644 --- a/apps/hasensors/boot.js +++ b/apps/hasensors/boot.js @@ -1,6 +1,8 @@ (function () { - const sb = () => require("hasensors").sendBattery(); - Bangle.on("charging", sb); - NRF.on("connect", () => setTimeout(sb, 2000)); - setInterval(sb, 10 * 60 * 1000); -})(); \ No newline at end of file + const su = () => require("hasensors").sendUpdate(); + Bangle.on("charging", su); + NRF.on("connect", () => setTimeout(su, 2000)); + su(); + setInterval(su, 10 * 60 * 1000); + Bangle.on('HRM', h=>require("hasensors").sendHRM(h)); +})(); diff --git a/apps/hasensors/lib.js b/apps/hasensors/lib.js index 83072262c..5a0cf0cab 100644 --- a/apps/hasensors/lib.js +++ b/apps/hasensors/lib.js @@ -12,9 +12,8 @@ function post(sensor, data) { }); } -exports.sendBattery = function () { - if (!NRF.getSecurityStatus().connected) return; - const b = E.getBattery(), +function sendBattery() { + const b = E.getBattery(), c = Bangle.isCharging(); let i = "mdi:battery"; if (c) i += "-charging"; @@ -40,4 +39,75 @@ exports.sendBattery = function () { icon: i, } }); -} \ No newline at end of file +} + +function sendSteps() { + post("steps", { + state: Bangle.getStepCount(), + attributes: { + friendly_name: "{name} Step Count", + unit_of_measurement: "steps", + state_class: "total", + icon: "mdi:shoe-print", + } + }); +} + +/** + * Sends pressure *and temperature* + */ +function sendPressure() { + if (!Bangle.getPressure) return; // not a Bangle 2 + const promise = Bangle.getPressure(); + if (!promise) return; // emulator? + promise.then(values=>{ + post("pressure", { + state: Math.round(values.pressure*10)/10, + attributes: { + friendly_name: "{name} Pressure", + unit_of_measurement: "hPa", + device_class: "atmospheric pressure", + state_class: "measurement", + icon: "mdi:gauge", + } + }); + post("temperature", { + state: Math.round(values.temperature*10)/10, + attributes: { + friendly_name: "{name} Temperature", + unit_of_measurement: "°C", + device_class: "temperature", + state_class: "measurement", + icon: "mdi:thermometer", + } + }); + }); +} + +exports.sendUpdate = function() { + if (!NRF.getSecurityStatus().connected) return; + sendBattery(); + sendSteps(); + sendPressure(); +} + + +let hrm_last = 0; +const HRM_INTERVAL = 10*60*1000; +exports.sendHRM = function (hrm) { + if (!NRF.getSecurityStatus().connected) return; + const now = (new Date).getTime(); + if (hrm_last > now-HRM_INTERVAL) return; + post("hrm", { + state: hrm.bpm, + attributes: { + confidence: hrm.confidence, + raw: hrm.raw, + friendly_name: "{name} Heart Rate", + icon: "mdi:heart", + unit_of_measurement: "bpm", + state_class: "measurement", + } + }); + hrm_last = now; +}; diff --git a/apps/hasensors/metadata.json b/apps/hasensors/metadata.json index 5764c6100..550095c76 100644 --- a/apps/hasensors/metadata.json +++ b/apps/hasensors/metadata.json @@ -2,7 +2,7 @@ "id": "hasensors", "name": "Home Assistant Sensors", "shortName": "HA sensors", - "version": "0.02", + "version": "0.03", "description": "Send sensor values to Home Assistant using Android Integration/Gadgetbridge", "icon": "ha.png", "type": "bootloader", diff --git a/apps/kbedgewrite/ChangeLog b/apps/kbedgewrite/ChangeLog index e6dd4b19e..93f9336cf 100644 --- a/apps/kbedgewrite/ChangeLog +++ b/apps/kbedgewrite/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Accents and extended mode characters +0.03: Bugfix - draw initial text after the back button has been removed diff --git a/apps/kbedgewrite/lib.js b/apps/kbedgewrite/lib.js index d71ad5c73..62e699fa7 100644 --- a/apps/kbedgewrite/lib.js +++ b/apps/kbedgewrite/lib.js @@ -352,11 +352,6 @@ exports.input = function(options) { } }; - // Draw initial string - require("widget_utils").hide(); - g.setBgColor(g.theme.bg); - wrapText(); - draw(); return new Promise((resolve,reject) => { Bangle.setUI({ @@ -385,6 +380,13 @@ exports.input = function(options) { } } }); + + // Draw initial string + require("widget_utils").hide(); + g.setBgColor(g.theme.bg); + wrapText(); + draw(); + }); diff --git a/apps/kbedgewrite/metadata.json b/apps/kbedgewrite/metadata.json index 717cdbcba..01436c6aa 100644 --- a/apps/kbedgewrite/metadata.json +++ b/apps/kbedgewrite/metadata.json @@ -1,6 +1,6 @@ { "id": "kbedgewrite", "name": "EdgeWrite keyboard", - "version":"0.02", + "version":"0.03", "description": "A library for text input via EdgeWrite swipe gestures", "icon": "app.png", "type":"textinput", diff --git a/apps/messagegui/ChangeLog b/apps/messagegui/ChangeLog index d0676ec9b..8df107555 100644 --- a/apps/messagegui/ChangeLog +++ b/apps/messagegui/ChangeLog @@ -111,3 +111,5 @@ Make sure play button image is transparent Add top-right menu to music playback to allow message to be deleted 0.82: Stop buzzing when a message is removed (e.g. call answered) +0.83: Add option to not open the first unread message +0.84: Fix: Assign show message entry to the settings menu and not the message itself. diff --git a/apps/messagegui/app.js b/apps/messagegui/app.js index 22f9c0579..21cd1c3e1 100644 --- a/apps/messagegui/app.js +++ b/apps/messagegui/app.js @@ -155,7 +155,7 @@ function showMapMessage(msg) { function back() { // mark as not new and return to menu msg.new = false; layout = undefined; - checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1,openMusic:0}); + checkMessages({clockIfNoMsg:1,clockIfAllRead:1,ignoreUnread:settings.ignoreUnread,openMusic:0}); } Bangle.setUI({mode:"updown", back: back}, back); // any input takes us back } @@ -195,8 +195,8 @@ function showMusicMessage(msg) { var wasNew = msg.new; msg.new = false; layout = undefined; - if (wasNew) checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:0,openMusic:0}); - else checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); + if (wasNew) checkMessages({clockIfNoMsg:1,clockIfAllRead:1,ignoreUnread:1,openMusic:0}); + else returnToMain(); } function updateLabels() { trackName = reduceStringAndPad(msg.track, trackScrollOffset, 13); @@ -283,7 +283,7 @@ function showMessageSettings(msg) { }; if (msg.id!="music") - msg[/*LANG*/"View Message"] = () => showMessageScroller(msg); + menu[/*LANG*/"View Message"] = () => showMessageScroller(msg); if (msg.reply && reply) { menu[/*LANG*/"Reply"] = () => { @@ -304,7 +304,7 @@ function showMessageSettings(msg) { menu = Object.assign(menu, { /*LANG*/"Delete" : () => { MESSAGES = MESSAGES.filter(m=>m.id!=msg.id); - checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); + returnToMain(); }, }); @@ -315,25 +315,25 @@ function showMessageSettings(msg) { Bangle.messageIgnore(msg); MESSAGES = MESSAGES.filter(m=>m.id!=msg.id); } - checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); + returnToMain(); }); }; menu = Object.assign(menu, { /*LANG*/"Mark Unread" : () => { msg.new = true; - checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); + returnToMain(); }, /*LANG*/"Mark all read" : () => { MESSAGES.forEach(msg => msg.new = false); - checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); + returnToMain(); }, /*LANG*/"Delete all messages" : () => { E.showPrompt(/*LANG*/"Are you sure?", {title:/*LANG*/"Delete All Messages"}).then(isYes => { if (isYes) { MESSAGES = []; } - checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); + returnToMain(); }); }, }); @@ -349,7 +349,7 @@ function showMessage(msgid, persist) { clearInterval(updateLabelsInterval); updateLabelsInterval=undefined; } - if (!msg) return checkMessages({clockIfNoMsg:1,clockIfAllRead:0,showMsgIfUnread:0,openMusic:openMusic}); // go home if no message found + if (!msg) return returnToClockIfEmpty(); // go home if no message found if (msg.id=="music") { cancelReloadTimeout(); // don't auto-reload to clock now return showMusicMessage(msg); @@ -399,7 +399,7 @@ function showMessage(msgid, persist) { layout = undefined; msg.new = false; // read mail cancelReloadTimeout(); // don't auto-reload to clock now - checkMessages({clockIfNoMsg:1,clockIfAllRead:0,showMsgIfUnread:0,openMusic:openMusic}); + returnToClockIfEmpty(); } var negHandler,posHandler,footer = [ ]; if (msg.negative) { @@ -407,7 +407,7 @@ function showMessage(msgid, persist) { msg.new = false; cancelReloadTimeout(); // don't auto-reload to clock now Bangle.messageResponse(msg,false); - checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1,openMusic:openMusic}); + returnToCheckMessages(); }; footer.push({type:"img",src:atob("PhAB4A8AAAAAAAPAfAMAAAAAD4PwHAAAAAA/H4DwAAAAAH78B8AAAAAA/+A/AAAAAAH/Af//////w/gP//////8P4D///////H/Af//////z/4D8AAAAAB+/AfAAAAAA/H4DwAAAAAPg/AcAAAAADwHwDAAAAAA4A8AAAAAAAA=="),col:"#f00",cb:negHandler}); } footer.push({fillx:1}); // push images to left/right @@ -421,7 +421,7 @@ function showMessage(msgid, persist) { Bluetooth.println(JSON.stringify(result)); replying = false; layout.render(); - checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1,openMusic:openMusic}); + returnToCheckMessages(); }) .catch(() => { replying = false; @@ -435,7 +435,7 @@ function showMessage(msgid, persist) { msg.new = false; cancelReloadTimeout(); // don't auto-reload to clock now Bangle.messageResponse(msg,true); - checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1,openMusic:openMusic}); + returnToCheckMessages(); }; footer.push({type:"img",src:atob("QRABAAAAAAAAAAOAAAAABgAAA8AAAAADgAAD4AAAAAHgAAPgAAAAAPgAA+AAAAAAfgAD4///////gAPh///////gA+D///////AD4H//////8cPgAAAAAAPw8+AAAAAAAfB/4AAAAAAA8B/gAAAAAABwB+AAAAAAADAB4AAAAAAAAABgAA=="),col:"#0f0",cb:posHandler}); } @@ -447,7 +447,7 @@ function showMessage(msgid, persist) { ]}, { type:"btn", src:require("messageicons").getImage(msg), - col:require("messageicons").getColor(msg, {settings:settings, default:g.theme.fg2}), + col:require("messageicons").getColor(msg, {settings, default:g.theme.fg2}), pad: 3, cb:()=>{ cancelReloadTimeout(); // don't auto-reload to clock now showMessageSettings(msg); @@ -476,7 +476,7 @@ function showMessage(msgid, persist) { /* options = { clockIfNoMsg : bool clockIfAllRead : bool - showMsgIfUnread : bool + ignoreUnread : bool // don't automatically navigate to the first unread message openMusic : bool // open music if it's playing dontStopBuzz : bool // don't stuf buzzing (any time other than the first this is undefined/false) } @@ -500,7 +500,7 @@ function checkMessages(options) { // we have >0 messages var newMessages = MESSAGES.filter(m=>m.new&&m.id!="music"); // If we have a new message, show it - if (options.showMsgIfUnread && newMessages.length) { + if (!options.ignoreUnread && newMessages.length) { delete newMessages[0].show; // stop us getting stuck here if we're called a second time showMessage(newMessages[0].id, false); // buzz after showMessage, so being busy during layout doesn't affect the buzz pattern @@ -538,7 +538,7 @@ function checkMessages(options) { } if (img) { var fg = g.getColor(), - col = require("messageicons").getColor(msg, {settings:settings, default:fg}); + col = require("messageicons").getColor(msg, {settings, default:fg}); g.setColor(col).drawImage(img, x+24, r.y+24, {rotate:0}) // force centering .setColor(fg); // only color the icon x += 50; @@ -570,6 +570,17 @@ function checkMessages(options) { }); } +function returnToCheckMessages(clock) { + checkMessages({clockIfNoMsg:1,clockIfAllRead:1,ignoreUnread:settings.ignoreUnread,openMusic}); +} + +function returnToMain() { + checkMessages({clockIfNoMsg:0,clockIfAllRead:0,ignoreUnread:1,openMusic:0}); +} + +function returnToClockIfEmpty() { + checkMessages({clockIfNoMsg:1,clockIfAllRead:0,ignoreUnread:1,openMusic}); +} function cancelReloadTimeout() { if (!unreadTimeout) return; @@ -594,7 +605,7 @@ setTimeout(() => { // only openMusic on launch if music is new, or state=="show" (set by messagesmusic) var musicMsg = MESSAGES.find(m => m.id === "music"); checkMessages({ - clockIfNoMsg: 0, clockIfAllRead: 0, showMsgIfUnread: 1, + clockIfNoMsg: 0, clockIfAllRead: 0, ignoreUnread: settings.ignoreUnread, openMusic: ((musicMsg&&musicMsg.new) && settings.openMusic) || (musicMsg&&musicMsg.state=="show"), dontStopBuzz: 1 }); }, 10); // if checkMessages wants to 'load', do that diff --git a/apps/messagegui/metadata.json b/apps/messagegui/metadata.json index 4e3ca6057..3e0538d9e 100644 --- a/apps/messagegui/metadata.json +++ b/apps/messagegui/metadata.json @@ -2,7 +2,7 @@ "id": "messagegui", "name": "Message UI", "shortName": "Messages", - "version": "0.82", + "version": "0.84", "description": "Default app to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index 052916e64..0973caea0 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -5,4 +5,7 @@ 0.59: fixes message timeout by using setinterval, as it was intended. So the buzz is triggered every x seconds until the timeout occours. 0.60: Bump version to allow new buzz.js module to be loaded - fixes memory/performance hog when buzz called 0.61: Add repeatCalls option to allow different repeat settings for messages vs calls -0.62: Add option for driving on left (affects roundabout icons in navigation) \ No newline at end of file +0.62: Add option for driving on left (affects roundabout icons in navigation) +0.63: Add option to not open the first unread message +0.64: Only load from storage once in settings +0.65: Fix settings error introduced by two conflicting changes diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 8197081bb..cc46b93dc 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.62", + "version": "0.65", "description": "Library to handle, load and store message events received from Android/iOS", "icon": "app.png", "type": "module", diff --git a/apps/messages/settings.js b/apps/messages/settings.js index 4ccc47237..dcec01d40 100644 --- a/apps/messages/settings.js +++ b/apps/messages/settings.js @@ -1,7 +1,7 @@ (function(back) { const iconColorModes = ['color', 'mono']; - function settings() { + function loadSettings() { let settings = require('Storage').readJSON("messages.settings.json", true) || {}; if (settings.vibrate===undefined) settings.vibrate=":"; if (settings.vibrateCalls===undefined) settings.vibrateCalls=":"; @@ -11,6 +11,7 @@ if (settings.unreadTimeout===undefined) settings.unreadTimeout=60; if (settings.maxMessages===undefined) settings.maxMessages=3; if (settings.iconColorMode === undefined) settings.iconColorMode = iconColorModes[0]; + if (settings.ignoreUnread === undefined) settings.ignoreUnread = 0; settings.unlockWatch=!!settings.unlockWatch; settings.openMusic=!!settings.openMusic; settings.maxUnreadTimeout=240; @@ -18,80 +19,84 @@ return settings; } function updateSetting(setting, value) { - let settings = require('Storage').readJSON("messages.settings.json", true) || {}; settings[setting] = value; require('Storage').writeJSON("messages.settings.json", settings); } + var settings = loadSettings(); var mainmenu = { "" : { "title" : /*LANG*/"Messages" }, "< Back" : back, - /*LANG*/'Vibrate': require("buzz_menu").pattern(settings().vibrate, v => updateSetting("vibrate", v)), - /*LANG*/'Vibrate for calls': require("buzz_menu").pattern(settings().vibrateCalls, v => updateSetting("vibrateCalls", v)), + /*LANG*/'Vibrate': require("buzz_menu").pattern(settings.vibrate, v => updateSetting("vibrate", v)), + /*LANG*/'Vibrate for calls': require("buzz_menu").pattern(settings.vibrateCalls, v => updateSetting("vibrateCalls", v)), /*LANG*/'Repeat': { - value: settings().repeat, + value: settings.repeat, min: 0, max: 10, format: v => v?v+"s":/*LANG*/"Off", onchange: v => updateSetting("repeat", v) }, /*LANG*/'Repeat for calls': { - value: settings().repeatCalls, + value: settings.repeatCalls, min: 0, max: 10, format: v => v?v+"s":/*LANG*/"Off", onchange: v => updateSetting("repeatCalls", v) }, /*LANG*/'Vibrate timer': { - value: settings().vibrateTimeout, - min: 0, max: settings().maxUnreadTimeout, step : 10, + value: settings.vibrateTimeout, + min: 0, max: settings.maxUnreadTimeout, step : 10, format: v => v?v+"s":/*LANG*/"Off", onchange: v => updateSetting("vibrateTimeout", v) }, /*LANG*/'Unread timer': { - value: settings().unreadTimeout, - min: 0, max: settings().maxUnreadTimeout, step : 10, + value: settings.unreadTimeout, + min: 0, max: settings.maxUnreadTimeout, step : 10, format: v => v?v+"s":/*LANG*/"Off", onchange: v => updateSetting("unreadTimeout", v) }, /*LANG*/'Min Font': { - value: 0|settings().fontSize, + value: 0|settings.fontSize, min: 0, max: 1, format: v => [/*LANG*/"Small",/*LANG*/"Medium"][v], onchange: v => updateSetting("fontSize", v) }, + /*LANG*/'Auto-Open Unread Msg': { + value: !!settings.ignoreUnread, + onchange: v => updateSetting("ignoreUnread", v) + }, /*LANG*/'Auto-Open Music': { - value: !!settings().openMusic, + value: !!settings.openMusic, onchange: v => updateSetting("openMusic", v) }, /*LANG*/'Unlock Watch': { - value: !!settings().unlockWatch, + value: !!settings.unlockWatch, onchange: v => updateSetting("unlockWatch", v) }, /*LANG*/'Flash Icon': { - value: !!settings().flash, + value: !!settings.flash, onchange: v => updateSetting("flash", v) }, /*LANG*/'Quiet mode disables auto-open': { - value: !!settings().quietNoAutOpn, + value: !!settings.quietNoAutOpn, onchange: v => updateSetting("quietNoAutOpn", v) }, /*LANG*/'Disable auto-open': { - value: !!settings().noAutOpn, + value: !!settings.noAutOpn, onchange: v => updateSetting("noAutOpn", v) }, /*LANG*/'Widget messages': { - value:0|settings().maxMessages, + value:0|settings.maxMessages, min: 0, max: 5, format: v => v ? v :/*LANG*/"Hide", onchange: v => updateSetting("maxMessages", v) }, /*LANG*/'Icon color mode': { - value: Math.max(0,iconColorModes.indexOf(settings().iconColorMode)), + value: Math.max(0,iconColorModes.indexOf(settings.iconColorMode)), min: 0, max: iconColorModes.length - 1, format: v => iconColorModes[v], onchange: v => updateSetting("iconColorMode", iconColorModes[v]) }, /*LANG*/'Car driver pos': { // used by messagegui - value:!!settings().carIsRHD, + value:!!settings.carIsRHD, format: v => v ? /*LANG*/"Right" :/*LANG*/"Left", onchange: v => updateSetting("carIsRHD", v) }, diff --git a/apps/mylocation/interface.html b/apps/mylocation/interface.html index 1bd3129ee..78141c400 100644 --- a/apps/mylocation/interface.html +++ b/apps/mylocation/interface.html @@ -2,6 +2,7 @@ +