From ca65ff6be6591b90798f2df510c5cad27f88b44e Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 17:50:07 +0100 Subject: [PATCH 01/48] Create app.js --- apps/BLEcontroller/app.js | 424 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 424 insertions(+) create mode 100644 apps/BLEcontroller/app.js diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js new file mode 100644 index 000000000..a486917cf --- /dev/null +++ b/apps/BLEcontroller/app.js @@ -0,0 +1,424 @@ +/* + +========================================================== + +Simple event based robot controller that enables robot +to switch into automatic or manual control modes. Behaviours +are controlled via a simple finite state machine. + +In automatic mode the +robot will look after itself. In manual mode, the watch +will provide simple forward, back, left and right commands. +The messages will be transmitted to a partner BLE Espruino +using BLE + +Written by Richard Hopkins, May 2020 + +========================================================== + +declare global variables for watch button statuses */ +top_btn = false; +middle_btn = false; +left_btn= false; // the left side of the touch screen +right_btn = false; // the right side of the touch screen +bottom_btn = false; + +/* + +CONFIGURATION AREA - STATE VARIABLES + +declare global variables for the toggle button +statuses; if you add an additional toggle button +you should declare it and initiase it here */ + +var status_auto = {value: false}; +var status_mic = {value: true}; +var status_spk = {value: true}; + +/* trsnsmit message */ +const transmit = (state,object,status) => { + message = { + state: state, + obj: object, + val: status, + }; + print(message); + return JSON.stringify(message); +}; + +/* + +CONFIGURATION AREA - ICON DEFINITIONS + +Retrieve 30px PNG icons from: +https://icons8.com/icon/set/speak/ios-glyphs + +Create icons using: +https://www.espruino.com/Image+Converter +Use compression: true +Transparency: true +Diffusion: flat +Colours: 16bit RGB +Ouput as: Image Object + +Add an additional element to the icons array +with a unique name and the data from the Image Object +*/ +const icons = [ + { + name: "walk", + data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" + }, + { + name: "sit", + data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" + }, + { + name: "joystick", + data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" + }, + { + name: "left", + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + }, + { + name: "right", + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + }, + { + name: "forward", + data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" + }, + { + name: "backward", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" + }, + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "spk_on", + data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" + }, + { + name: "spk_off", + data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" + }, + { + name: "mic_on", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" + }, + { + name: "mic_off", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Wf47/HJZLjHZ45RHrI7NHJYhLHqoZJA54hNHr5lTXL6vPSra5jKbo9REZrLRHa5DTXp47jAA7TTF7INLRqY7fdKavhXKo5te6wA==" + }, + { + name: "comms", + data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + } +]; + +/* finds icon data by name in the icon array and returns an image object*/ +const drawIcon = (name) => { + for (var icon of icons) { + if (icon.name == name) { + image = { + width : 30, height : 30, bpp : 16, + transparent : 1, + buffer: require("heatshrink").decompress(atob(icon.data)) + }; + return image;} + } +}; + +/* + +CONFIGURATION AREA - BUTTON DEFINITIONS + +for a simple button, just define a primary colour +and an icon name from the icon array and +the text to display beneath the button + +for toggle buttons, additionally provide secondary +colours, icon name and text. Also provide a reference +to a global variable for the value of the button. +The global variable should be declared at the start of +the program and it may be adviable to use the 'status_name' +format to ensure it is clear. + +*/ +var joystickBtn = { + primary_colour: 0x653E, + primary_icon: 'joystick', + primary_text: 'Joystick', + }; + +var turnLeftBtn = { + primary_colour: 0x653E, + primary_text: 'Left', + primary_icon: 'left', + }; + +var turnRightBtn = { + primary_colour: 0x33F9, + primary_text: 'Right', + primary_icon: 'right', + }; + +var autoBtn = { + primary_colour: 0xE9C7, + primary_text: 'Stop', + primary_icon: 'sit', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Move', + secondary_icon : 'walk', + value: status_auto + }; + +var micBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'mic_off', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'mic_on', + value: status_mic + }; + +var spkBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'spk_off', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'spk_on', + value: status_spk + }; + +/* + +CONFIGURATION AREA - SCREEN DEFINITIONS + +a screen can have a button (as defined above) +on the left and/or the right of the screen. + +in adddition a screen can optionally have +an icon for each of the three buttons on +the left hand side of the screen. These +are defined as btn1, bt2 and bt3. The +values are names from the icon array. + +*/ +const menuScreen = { + left: autoBtn, + right: joystickBtn, + btn1: "comms" +}; + +const joystickScreen = { + left: turnLeftBtn, + right: turnRightBtn, + btn1: "forward", + btn2: "backward", + btn3: "back" +}; + +const commsScreen = { + left: micBtn, + right: spkBtn, + btn3: "back" +}; + +/* base state definition + +Each of the screens correspond to a state; +this class provides a constuctor for each +of the states + +*/ +class State { + constructor(params) { + this.state = params.state; + this.events = params.events; + this.screen = params.screen; + } +} + +/* + +CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS + +This area defines how each screen behaves. + +Each screen corresponds to a different State of the +state machine. This makes it much easier to isolate +behaviours between screens. + +The state value is transmitted whenever a button is pressed +to provide context (so the receiving device, knows which +button was pressed on which screen). + +The screens are defined above. + +The events section identifies if a particular button has been +pressed and released on the screen and an action can then be taken. + +The events function receives a notification from a mySetWatch which +provides an event object that identifies which button and whether +it has been pressed down or released. Actions can then be taken. +The events function will always return a State object. + +If the events function returns different State from the current +one, then the state machine will change to that new State and redrsw +the screen appropriately. + +To add in additional capabilities for button presses, simply add +an additional 'if' statement. + +For toggle buttons, the value of the sppropiate status object is +inversed and the new value transmitted. + +*/ + +/* The Home State/Page is where the application beings */ +const Home = new State({ + state: "Home", + screen: menuScreen, + events: (event) => { + if ((event.object == "right") && (event.status == "end")) { + transmit("Joystick", "joystick", "on"); + return Joystick; + } + if ((event.object == "top") && (event.status == "end")) { + return Comms; + } + if ((event.object == "left") && (event.status == "end")) { + status_auto.value = !status_auto.value; + transmit(this.state, "auto", onOff(status_auto.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* Joystick page state */ +const Joystick = new State({ + state: "Joystick", + screen: joystickScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + transmit("Joystick", "joystick", "off"); + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* Comms page state */ +const Comms = new State({ + state: "Comms", + screen: commsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "left") && (event.status == "end")) { + status_mic.value = !status_mic.value; + transmit(this.state, "mic", onOff(status_mic.value)); + return this; + } + if ((event.object == "right") && (event.status == "end")) { + status_spk.value = !status_spk.value; + transmit(this.state, "spk", onOff(status_spk.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* translate button status into english */ +const startEnd = status => status ? "start" : "end"; + +/* translate status into english */ +const onOff= status => status ? "on" : "off"; + + +/* create watching functions that will change the global +button status when pressed or released + +This is actuslly the hesrt of the program. When a button +is not being pressed, nothing is happening (no loops). +This makes the progrsm more battery efficient. + +When a setWatch event is raised, the custom callbacks defined +here will be called. These then fired as events to the current +state/screen of the state mschine. + +Some events, will result in the stste of the state machine +chsnging, which is why the screen is redrswn after each +button press. + +*/ +const setMyWatch = (params) => { + setWatch(() => { + params.bool=!params.bool; + machine = machine.events({object: params.label, status: startEnd(params.bool)}); + drawScreen(machine.screen); + }, params.btn, {repeat:true, edge:"both"}); +}; + +/* object array used to set up the watching functions +*/ +const buttons = [ + {bool : bottom_btn, label : "bottom",btn : BTN3}, + {bool : middle_btn, label : "mdiddle",btn : BTN2}, + {bool : top_btn, label : "top",btn : BTN1}, + {bool : left_btn, label : "left",btn : BTN4}, + {bool : right_btn, label : "right",btn : BTN5} + ]; + +/* set up watchers for buttons */ +for (var button of buttons) + {setMyWatch(button);} + +/* Draw various kinds of buttons */ +const drawButton = (params,side) => { + g.setFontAlign(0,1); + icon = drawIcon(params.primary_icon); + text = params.primary_text; + g.setColor(params.primary_colour); + const x = (side == "left") ? 0 : 120; + if ((params.toggle) && (params.value.value)) { + g.setColor(params.secondary_colour); + text = params.secondary_text; + icon = drawIcon(params.secondary_icon); + } + g.fillRect(0+x,24,119+x, 239); + g.setColor(0x000); + g.setFont("Vector",15); + g.setFontAlign(0,0.0); + g.drawString(text,60+x,160); + options = {rotate: 0, scale:2}; + g.drawImage(icon,x+60,120,options); +}; + +/* Draw the pages corresponding to the states */ +const drawScreen = (params) => { + drawButton(params.left,'left'); + drawButton(params.right,'right'); + g.setColor(0x000); + if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} + if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} + if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} +}; + +machine = Home; // instantiate the state machine at Home +Bangle.drawWidgets(); // draw active widgets +drawScreen(machine.screen); // draw the screen From 033b227e674a50e55a1bdc356bedc90045c18dd9 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 17:56:05 +0100 Subject: [PATCH 02/48] Create app-icon.js --- apps/BLEcontroller/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/BLEcontroller/app-icon.js diff --git a/apps/BLEcontroller/app-icon.js b/apps/BLEcontroller/app-icon.js new file mode 100644 index 000000000..da959f36a --- /dev/null +++ b/apps/BLEcontroller/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("nk8wkBiIA/AH4A/AA8QaIYdYd4gOLG5odMBhYcHCBAuEgJVVDqQLHCA0BNpA6QSYgd5LLYaFSq4dQLR4wJLyQdKQJBbOJZwdYBxypRS6AdZJZ4drPH54/PH541DjIdCDjRaBDjYAhTITUeDy4cEDzAdXCwoANGh4ANIRASKFBQdRBZodtLLq0TDv4dZAH4A/AH4ArA==")) From 0e67901c39932c90cf93d9529f50d13f959a7042 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 17:59:52 +0100 Subject: [PATCH 03/48] Update app-icon.js --- apps/BLEcontroller/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app-icon.js b/apps/BLEcontroller/app-icon.js index da959f36a..db64a917d 100644 --- a/apps/BLEcontroller/app-icon.js +++ b/apps/BLEcontroller/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("nk8wkBiIA/AH4A/AA8QaIYdYd4gOLG5odMBhYcHCBAuEgJVVDqQLHCA0BNpA6QSYgd5LLYaFSq4dQLR4wJLyQdKQJBbOJZwdYBxypRS6AdZJZ4drPH54/PH541DjIdCDjRaBDjYAhTITUeDy4cEDzAdXCwoANGh4ANIRASKFBQdRBZodtLLq0TDv4dZAH4A/AH4ArA==")) +E.toArrayBuffer(atob("PDyEARERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERAAAAAAEREREREREREREREREREREREREREREREREQAAAAAAEREREREREREREQAAEREREREREREREAAAAAAAAAAAERERERERERERAAAAABERERERERERAAAAAAAAAAAAEREREREREREQAAAAAAERERERERERAAAAAAAREREREREREREREREQAAAAAAERERERERERAAAAAAEREREREREREREREREAAAEQAAAAAAAAAAAAAAAAABEREREREREREREREREAABERAAAAAAAAAAAAAAAAABEREREREREREREREREAABERAAAAAAAAAAAAAAAAABEREREREREREREREREAAAEQAAAAAAAAAAAAAAAAABEREREREREREREREREQAAAAAAARERERERERAAAAAAEREREREREREREREREQAAAAAAARERERERERAAAAAAARERERERERERERERERAAAAAAABERERERERAAAAAAAAAAAAEREREREREREREQAAAAABEREREREREAAAAAAAAAAAERERERERERERERAAAAAAEREREREREREREQAAAAAAERERERERERERERAAAAAAERERERERERERERAAAAAAEREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREQAAAAABEREREREREREREREREREREREREREREREREQAAAAABERERERERERERERERERERERERERERERERERAAAAAAERERERERERERERERERERERERERERERERERAAAAAAEREREREREREREREREREREREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREQAAAAABEREREREREREREREREREREREREREREREREQAAAAABERERERERERERERERERERERERERERERERERAAAAAAERERERERERERERERERERERERERERERERERAAAAAAEREREREREREREREREREREREREREREREREREAAAAREREREREREREREREREREREREREREREREREREAABEREREREREREREREREREREREREREREREREREREQEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREQAAABERERERERERERERERERERERERERERERERERAAAAAAAREREREREREREREREREREREREREREREREAAAAAAAAAEREREREREREREREREREREREREREREREAAAAAAAAAERERERERERERERERERERERAAAAAAAAAAAAAAAAAAAAAAAAAAAREREREREREREQAAAAAAAAAAAAAAAAAAAAAAAAAAABEREREREREREAAAAAAAAAAAAAARAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAEREAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAEREAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAARAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREQ==")) From ed20c802da0f7b577754d37c4e439be01cc54290 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:01:52 +0100 Subject: [PATCH 04/48] Add files via upload --- apps/BLEcontroller/BLEcontroller.png | Bin 0 -> 579 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/BLEcontroller/BLEcontroller.png diff --git a/apps/BLEcontroller/BLEcontroller.png b/apps/BLEcontroller/BLEcontroller.png new file mode 100644 index 0000000000000000000000000000000000000000..df529e982df191f6cd16e13b91503880546e3b05 GIT binary patch literal 579 zcmV-J0=)f+P)0&l=6uncr60#<-4LD4u}oUzxLt0>JPsZnf=H(GxN=RY=~QshW#_o)vQwR6Y53F~sJV_j|%*5y{mx(s~cZ7WuRX_Eh7pF8SZ{s6XtF}HHkrwH5v6Rw41 zNv~@GuIa$r4sHRLz>^=B{%f=THUEMs;D+eweGN>yk*LQe-jt3q8=UAHE`(~Zj@)Qt ztU1v8g9121lQz+evKsB_gZkjyq`k;P$V1t$Rs%<)Kikb8MP#4*f0#kFbpFtz5!vGy!T@R R(GCCr002ovPDHLkV1mbo0=NJG literal 0 HcmV?d00001 From 89a49189f4c4694a971e332b69a0a62a569e6900 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:07:04 +0100 Subject: [PATCH 05/48] Update apps.json --- apps.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps.json b/apps.json index 04c2f637d..6385082f6 100644 --- a/apps.json +++ b/apps.json @@ -1760,5 +1760,20 @@ { "name": "jbm8b.img", "url": "app-icon.js", "evaluate": true } ], "version": "0.03" + }, +{ + "id": "BLEcontroller", + "name": "BLE Robot Controller with Joystick", + "shortName": "BLE Controller", + "icon": "BLEcontroller.png", + "version": "0.01", + "description": "A configurable controller for BLE robots, including a basic joystick.", + "tags": "tools", + "readme": "README.md", + "allow_emulator":true, + "storage": [ + { "name": "BLEcontroller.app.js", "url": "app.js" }, + { "name": "BLEcontroller.img", "url": "app-icon.js", "evaluate": true } + ] } ] From 6bf2b7d9691d224b8fdf33b557a378fa6f06e9fd Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:09:54 +0100 Subject: [PATCH 06/48] Create README.md --- apps/BLEcontroller/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 apps/BLEcontroller/README.md diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md new file mode 100644 index 000000000..172bb1758 --- /dev/null +++ b/apps/BLEcontroller/README.md @@ -0,0 +1,3 @@ +=== BLE Controller +==Some text += More text From 0d013efb8e1c342a187c54027a75f88fe2acbcd2 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:13:23 +0100 Subject: [PATCH 07/48] Update app-icon.js --- apps/BLEcontroller/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app-icon.js b/apps/BLEcontroller/app-icon.js index db64a917d..0f5e1aff6 100644 --- a/apps/BLEcontroller/app-icon.js +++ b/apps/BLEcontroller/app-icon.js @@ -1 +1 @@ -E.toArrayBuffer(atob("PDyEARERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERAAAAAAEREREREREREREREREREREREREREREREREQAAAAAAEREREREREREREQAAEREREREREREREAAAAAAAAAAAERERERERERERAAAAABERERERERERAAAAAAAAAAAAEREREREREREQAAAAAAERERERERERAAAAAAAREREREREREREREREQAAAAAAERERERERERAAAAAAEREREREREREREREREAAAEQAAAAAAAAAAAAAAAAABEREREREREREREREREAABERAAAAAAAAAAAAAAAAABEREREREREREREREREAABERAAAAAAAAAAAAAAAAABEREREREREREREREREAAAEQAAAAAAAAAAAAAAAAABEREREREREREREREREQAAAAAAARERERERERAAAAAAEREREREREREREREREQAAAAAAARERERERERAAAAAAARERERERERERERERERAAAAAAABERERERERAAAAAAAAAAAAEREREREREREREQAAAAABEREREREREAAAAAAAAAAAERERERERERERERAAAAAAEREREREREREREQAAAAAAERERERERERERERAAAAAAERERERERERERERAAAAAAEREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREQAAAAABEREREREREREREREREREREREREREREREREQAAAAABERERERERERERERERERERERERERERERERERAAAAAAERERERERERERERERERERERERERERERERERAAAAAAEREREREREREREREREREREREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREQAAAAABEREREREREREREREREREREREREREREREREQAAAAABERERERERERERERERERERERERERERERERERAAAAAAERERERERERERERERERERERERERERERERERAAAAAAEREREREREREREREREREREREREREREREREREAAAAREREREREREREREREREREREREREREREREREREAABEREREREREREREREREREREREREREREREREREREQEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREQAAABERERERERERERERERERERERERERERERERERAAAAAAAREREREREREREREREREREREREREREREREAAAAAAAAAEREREREREREREREREREREREREREREREAAAAAAAAAERERERERERERERERERERERAAAAAAAAAAAAAAAAAAAAAAAAAAAREREREREREREQAAAAAAAAAAAAAAAAAAAAAAAAAAABEREREREREREAAAAAAAAAAAAAARAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAEREAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAEREAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAARAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREQ==")) +E.toArrayBuffer(atob("QECEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEREREhEhEREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAREREj////MzIREREAAAAAAAAAAAAAAAAAAAAAAAAAARERP//////zMzIRERAAAAAAAAAAAAAAAAAAAAAAAAARES/////////zMzIREQAAAAAAAAAAAAAAAAAAAAAAARET//////////8zMzEREAAAAAAAAAAAAAAAAAAAAAARET////////////MzMxERAAAAAAAAAAAAAAAAAAAAABET/////////////zMzMREAAAAAAAAAAAAAAAAAAAABES//////////////8zMyERAAAAAAAAAAAAAAAAAAABES///////////////zMzMREQAAAAAAAAAAAAAAAAAAERP//////zMzMzP///8zMzERAAAAAAAAAAAAAAAAAAARL//////zMzMzMz///zMzMhEAAAAAAAAAAAAAAAAAARE//////zM///MzM///8zMyERAAAAAAAAAAAAAAAAABEf/////zM///8zMzP//zMzMREAAAAAAAAAAAAAAAAAES//////M////zMzM///MzMxEQAAAAAAAAAAAAAAAAARL/////8z//MzMzMz///zMzIRAAAAAAAAAAAAAAAAARE//////zP/8zMzMzP///MzMhEQAAAAAAAAAAAAAAABET//////M//zMzMzM///8zMyERAAAAAAAAAAAAAAAAERP/////8zPzMzMzMz///zMzMREAAAAAAAAAAAAAAAARE//////zMzMzMzMzP///MzMxEQAAAAAAAAAAAAAAABET//////MzMzMzMzM///8zMzERAAAAAAAAAAAAAAAAERP//////zMzMzMzM////zMzMREAAAAAAAAAAAAAAAARE///////8zMzMzM/////MzMxEQAAAAAAAAAAAAAAABET////////MzMzM/////8zMyERAAAAAAAAAAAAAAABERE/////////8z///////zMyEREQAAAAAAAAAAAAAAERERP/////////////////MzERERAAAAAAAAAAAAAAERIhEv////////////////8zIRIhEQAAAAAAAAAAAAARH/ER/////////////////zMRH/ERAAAAAAAAAAAAABESIRL/////////////////MyESIREAAAAAAAAAAAAAERERE/////////////////8zMREREQAAAAAAAAAAAAAREREv/////////////////zMyERERAAAAAAAAAAAAARERE///////////////////MzMhEREQAAAAAAAAAAARERET//////////////////8zMzEREREAAAAAAAAAABEQERP//////////////////zMzMREBEQAAAAAAAAABERARE///////////////////MzMxEQEREAAAAAAAABERABET//////////////////8zMzERABERAAAAAAERERAAERP//////////////////zMzMREAAREREAAAEREREAARE///////////////////MzMxEQABERERAAEREREQABET//////////////////8zMzERAAEREREQAREzERAAERP//////////////////zMzMREAAREAERABEf8REAARE///////////////////MzMxEQABEQAREAEREREQABET//////////////////8zMzERAAEREREQABEREQAAERP/8///P/8z//P/8z//PzMzMREAABEREQAAARERAAARE//zP/M//zP/Mz/zP/MzMzMxEQAAEREQAAAAAREAABET//P//z//M//z//M//z8zMzERAAAREAAAAAABEQAAERP//////////////////zMzMREAABEQAAAAAAEREAAREv//////////////////MzMhEQABERAAAAAAABEQAAEREREREREREREREREREREREREQAAERAAAAAAAAEREAABEREREREREREREREREREREREQAAEREAAAAAAAARERAAAREREREREREREREREREREREQAAEREQAAAAAAAREREQAAAAAAAAEREREREREREQAAAAAAEREREAAAAAAREREREAAAAAAAAREREREREREREAAAAAERERERAAAAABEQABEQAAAAAAABERERERERERERAAAAAREAAREAAAAAEQAAERAAAAAREREREREREREREREAAAABEAABEQAAAAARAAABEAAAARERERERERERERERERAAAAEQAAARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")) From 0bb93839e65d107a5a56d105199ac80a55740e64 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:14:17 +0100 Subject: [PATCH 08/48] Add files via upload --- apps/BLEcontroller/BLEcontroller.png | Bin 579 -> 3473 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/BLEcontroller/BLEcontroller.png b/apps/BLEcontroller/BLEcontroller.png index df529e982df191f6cd16e13b91503880546e3b05..e42fe5dae5a7bc3cfc4aa20380f5a036df9d081f 100644 GIT binary patch literal 3473 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 delta 572 zcmV-C0>k~08^Z)4iBL{Q4GJ0x0000DNk~Le0000y0000y2nGNE06P5Ha*-hve*ySO zL_t(&f$f?-OT%yw#(%zppx`Ll!AZYDK}5ktT@@$6$+4>-4uYRW2PwEnt>EqpBH}1I zh^~rOaS>mJq!5cu&g7DRD))n1+Hm(gy?>6TS1=62FboYAfOp_4BK`$Zv#N%BfD&*F zyaI2)DXkX?r}JJNp{T89bhe@1S;c+}|v zR)8x((Kub6LC3T@MM2THU2eua4jvwYNT&0+a!sk}RB+K{=eX#yQ>@EP!n)k*SeJhZ z>vF4OU2YQAA>3# zZUL9TlOLDyk*LQe-jt3q8=UAHE`(~Zj@)QttU1v8g9121lQz+ zevKsB_gZkjyq`k;P$V1t$Rs%<)Kikb8MP#4*f0#kFbpFtz5!vG61?|g1JMou0000< KMNUMnLSTYaZ~#sK From 673e1c3c7bb326b62c9f352713deb63259f43d11 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:18:08 +0100 Subject: [PATCH 09/48] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 6385082f6..afac26dba 100644 --- a/apps.json +++ b/apps.json @@ -1767,7 +1767,7 @@ "shortName": "BLE Controller", "icon": "BLEcontroller.png", "version": "0.01", - "description": "A configurable controller for BLE robots, including a basic joystick.", + "description": "A configurable controller for BLE robots, with a basic four direction joystick.", "tags": "tools", "readme": "README.md", "allow_emulator":true, From 077728de67e620ef4dc9f71c4e62642759406429 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:18:56 +0100 Subject: [PATCH 10/48] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index afac26dba..c3780cfeb 100644 --- a/apps.json +++ b/apps.json @@ -1768,7 +1768,7 @@ "icon": "BLEcontroller.png", "version": "0.01", "description": "A configurable controller for BLE robots, with a basic four direction joystick.", - "tags": "tools", + "tags": "tool,bluetooth", "readme": "README.md", "allow_emulator":true, "storage": [ From ba68904acf2e6a436794d40e4236d28d697c1dea Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:23:51 +0100 Subject: [PATCH 11/48] Update app-icon.js --- apps/BLEcontroller/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app-icon.js b/apps/BLEcontroller/app-icon.js index 0f5e1aff6..662f43c5c 100644 --- a/apps/BLEcontroller/app-icon.js +++ b/apps/BLEcontroller/app-icon.js @@ -1 +1 @@ -E.toArrayBuffer(atob("QECEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEREREhEhEREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAREREj////MzIREREAAAAAAAAAAAAAAAAAAAAAAAAAARERP//////zMzIRERAAAAAAAAAAAAAAAAAAAAAAAAARES/////////zMzIREQAAAAAAAAAAAAAAAAAAAAAAARET//////////8zMzEREAAAAAAAAAAAAAAAAAAAAAARET////////////MzMxERAAAAAAAAAAAAAAAAAAAAABET/////////////zMzMREAAAAAAAAAAAAAAAAAAAABES//////////////8zMyERAAAAAAAAAAAAAAAAAAABES///////////////zMzMREQAAAAAAAAAAAAAAAAAAERP//////zMzMzP///8zMzERAAAAAAAAAAAAAAAAAAARL//////zMzMzMz///zMzMhEAAAAAAAAAAAAAAAAAARE//////zM///MzM///8zMyERAAAAAAAAAAAAAAAAABEf/////zM///8zMzP//zMzMREAAAAAAAAAAAAAAAAAES//////M////zMzM///MzMxEQAAAAAAAAAAAAAAAAARL/////8z//MzMzMz///zMzIRAAAAAAAAAAAAAAAAARE//////zP/8zMzMzP///MzMhEQAAAAAAAAAAAAAAABET//////M//zMzMzM///8zMyERAAAAAAAAAAAAAAAAERP/////8zPzMzMzMz///zMzMREAAAAAAAAAAAAAAAARE//////zMzMzMzMzP///MzMxEQAAAAAAAAAAAAAAABET//////MzMzMzMzM///8zMzERAAAAAAAAAAAAAAAAERP//////zMzMzMzM////zMzMREAAAAAAAAAAAAAAAARE///////8zMzMzM/////MzMxEQAAAAAAAAAAAAAAABET////////MzMzM/////8zMyERAAAAAAAAAAAAAAABERE/////////8z///////zMyEREQAAAAAAAAAAAAAAERERP/////////////////MzERERAAAAAAAAAAAAAAERIhEv////////////////8zIRIhEQAAAAAAAAAAAAARH/ER/////////////////zMRH/ERAAAAAAAAAAAAABESIRL/////////////////MyESIREAAAAAAAAAAAAAERERE/////////////////8zMREREQAAAAAAAAAAAAAREREv/////////////////zMyERERAAAAAAAAAAAAARERE///////////////////MzMhEREQAAAAAAAAAAARERET//////////////////8zMzEREREAAAAAAAAAABEQERP//////////////////zMzMREBEQAAAAAAAAABERARE///////////////////MzMxEQEREAAAAAAAABERABET//////////////////8zMzERABERAAAAAAERERAAERP//////////////////zMzMREAAREREAAAEREREAARE///////////////////MzMxEQABERERAAEREREQABET//////////////////8zMzERAAEREREQAREzERAAERP//////////////////zMzMREAAREAERABEf8REAARE///////////////////MzMxEQABEQAREAEREREQABET//////////////////8zMzERAAEREREQABEREQAAERP/8///P/8z//P/8z//PzMzMREAABEREQAAARERAAARE//zP/M//zP/Mz/zP/MzMzMxEQAAEREQAAAAAREAABET//P//z//M//z//M//z8zMzERAAAREAAAAAABEQAAERP//////////////////zMzMREAABEQAAAAAAEREAAREv//////////////////MzMhEQABERAAAAAAABEQAAEREREREREREREREREREREREREQAAERAAAAAAAAEREAABEREREREREREREREREREREREQAAEREAAAAAAAARERAAAREREREREREREREREREREREQAAEREQAAAAAAAREREQAAAAAAAAEREREREREREQAAAAAAEREREAAAAAAREREREAAAAAAAAREREREREREREAAAAAERERERAAAAABEQABEQAAAAAAABERERERERERERAAAAAREAAREAAAAAEQAAERAAAAAREREREREREREREREAAAABEAABEQAAAAARAAABEAAAARERERERERERERERERAAAAEQAAARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")) +E.toArrayBuffer(atob("MDCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAAAAAAAABERIQAAAAAAAAAAAAAAAAAAAAAAAAABERIRpiEQAAAAAAAAAAAAAAAAAAAAAAEREhOiImEqYAAAAAAAAAAAAAAAAAAAABESP///8zOFEQAAAAAAAAAAAAAAAAAAARI//////z8zp6AAAAAAAAAAAAAAAAAAES////////PzOFEAAAAAAAAAAAAAAAABEv////////8/MyGgAAAAAAAAAAAAAAARI//////////z8zIRAAAAAAAAAAAAAAARP/////8/P///M/IRAAAAAAAAAAAAAAES/////zgzM///M/OFEAAAAAAAAAAAAAET////84/zMzP/8z8hEAAAAAAAAAAAAAEf////M///gzP/8/MyEAAAAAAAAAAAABEv///zP/8zjzM/8/M4UQAAAAAAAAAAABEv///zP/M48zj//zPyEQAAAAAAAAAAABE////zP/ODMzj//zPyEQAAAAAAAAAAABE////zMzjyM48//zPyEQAAAAAAAAAAABE/////ODMzOPP/8/M4QQAAAAAAAAAAABE/////MzjzOD///zPyEQAAAAAAAAAAABE/////8zOPMz///zMzEQAAAAAAAAAAABEj//////PzP///8/MxhQAAAAAAAAAAARES////////////8/MRpyAAAAAAAAAAASMRP////////////zMRMhAAAAAAAAAAARMR////////////8/IRMhAAAAAAAAAAARES/////////////zMhp6AAAAAAAAAAEREv////////////8/MyEacAAAAAAAABERIv/////////////zPyERGAAAAAAAABEBE//////////////zPyEQEQAAAAAAAREBE//////////////zPyEQERAAAAABERABE//////////////zPyEQAREQAAEREgABE//////////////zPyEQABERIAESESABE//////////////zPyEQARESEAEfIRABE//////////////zPyEQAREBEAEREgABE//////z//////8/MzEQABERIAAREQABE/8/8z/zPz/z8/M/MzGAABERAAABEQABE/8/8/8/Pz/z8/PzPyEQABEQAAAAEQABE//////////////zPyEQABEAAAAAERAAETMzMzMzMjMzMzODIxEAAREAAAAAARAAEREhGmIRGhESaiYRKmEAARAAAAAAEREgABERIaYhEaERJqEmEQABERIAAAABERIaAAAAAAEREhGmIREAAAARESGgAAABEAARAAAAAAEREhGmIRGgAAARAAEQAAABEAARAAABERIRpiERoREgAAARAAEQAAAAAAAAAAABERIRpiERoREgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")) From dfc54d8d73703eb816ed2c37817c0a61a09e9edf Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:24:17 +0100 Subject: [PATCH 12/48] Add files via upload --- apps/BLEcontroller/BLEcontroller.png | Bin 3473 -> 2642 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/BLEcontroller/BLEcontroller.png b/apps/BLEcontroller/BLEcontroller.png index e42fe5dae5a7bc3cfc4aa20380f5a036df9d081f..3fa8575f30c5b25c3b1b21708de7281fed85de1c 100644 GIT binary patch literal 2642 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 A$p8QV literal 3473 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 From 0d8501f2d64e221ff80512cb819cdf4123c05141 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:26:13 +0100 Subject: [PATCH 13/48] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index c3780cfeb..ef6f68d11 100644 --- a/apps.json +++ b/apps.json @@ -1767,7 +1767,7 @@ "shortName": "BLE Controller", "icon": "BLEcontroller.png", "version": "0.01", - "description": "A configurable controller for BLE robots, with a basic four direction joystick.", + "description": "A configurable controller for BLE robots, with a basic four direction joystick. Easy to customise and add your own menus.", "tags": "tool,bluetooth", "readme": "README.md", "allow_emulator":true, From a38371d8d4e208552470718cf082c78e6e40f5df Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:36:54 +0100 Subject: [PATCH 14/48] Update README.md --- apps/BLEcontroller/README.md | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 172bb1758..a21db6240 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -1,3 +1,31 @@ -=== BLE Controller -==Some text -= More text +# BLE Robot Controller with Joystic + +A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. Amaze your friends by controlling your robot from your watch! + +Commands are sent from the Controller to the BLE robot in a JSON format. + +## Usage + +The application can be configured at will by chaning the definitions of the screens, events, icons and buttons. + +Most changes are possible via data, rather than code change. + +## Features + +In its default state, it has three screens that provide the ability to: +turn the robot on or off +turn on and off its voice and microphone +make the robot move by spinning left or right and moving forward and backwards + +## Controls + +The controls will vary by screen, but I suggest a convention of using BTN3 (the bottom button) for moving backwards up the menu stack. + +## Requests + +In the first instance, please consult my blog post on this application here. + +## Creator + +Richard Hopkins, FIET CEng +May 2020 From ce066c2a3852895a293df19fdaa3a2ca13bff37a Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:37:10 +0100 Subject: [PATCH 15/48] Update README.md --- apps/BLEcontroller/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index a21db6240..049a5f824 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -1,4 +1,4 @@ -# BLE Robot Controller with Joystic +# BLE Robot Controller with Joystick A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. Amaze your friends by controlling your robot from your watch! From 5df11d3c3d376902d01e782b883e0db7d1e094f7 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Fri, 22 May 2020 22:09:52 +0100 Subject: [PATCH 16/48] Working transmission --- .vscode/launch.json | 17 ++++++++++ apps/BLEcontroller/app.js | 68 +++++++++++++-------------------------- 2 files changed, 39 insertions(+), 46 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..771354e66 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/http-server" + } + ] +} \ No newline at end of file diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index a486917cf..3afae6b4b 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -1,21 +1,15 @@ /* - ========================================================== - Simple event based robot controller that enables robot to switch into automatic or manual control modes. Behaviours are controlled via a simple finite state machine. - In automatic mode the robot will look after itself. In manual mode, the watch will provide simple forward, back, left and right commands. The messages will be transmitted to a partner BLE Espruino using BLE - Written by Richard Hopkins, May 2020 - ========================================================== - declare global variables for watch button statuses */ top_btn = false; middle_btn = false; @@ -23,10 +17,10 @@ left_btn= false; // the left side of the touch screen right_btn = false; // the right side of the touch screen bottom_btn = false; +msgNum = 0; // message number + /* - CONFIGURATION AREA - STATE VARIABLES - declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ @@ -35,24 +29,32 @@ var status_auto = {value: false}; var status_mic = {value: true}; var status_spk = {value: true}; -/* trsnsmit message */ +/* trsnsmit message +where +s = first character of state, +o = first three character of object name +v = value of state.object +*/ + const transmit = (state,object,status) => { - message = { - state: state, - obj: object, - val: status, + msgNum ++; + msg = { + n: msgNum.toString().slice(-4), + s: state.substr(0,4), + o: object.substr(0,4), + v: status.substr(0.4), }; - print(message); - return JSON.stringify(message); + message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; + NRF.setAdvertising({},{ + showName: false, + manufacturer: 0x0590, + manufacturerData: JSON.stringify(message)}); }; /* - CONFIGURATION AREA - ICON DEFINITIONS - Retrieve 30px PNG icons from: https://icons8.com/icon/set/speak/ios-glyphs - Create icons using: https://www.espruino.com/Image+Converter Use compression: true @@ -60,7 +62,6 @@ Transparency: true Diffusion: flat Colours: 16bit RGB Ouput as: Image Object - Add an additional element to the icons array with a unique name and the data from the Image Object */ @@ -133,20 +134,16 @@ const drawIcon = (name) => { }; /* - CONFIGURATION AREA - BUTTON DEFINITIONS - for a simple button, just define a primary colour and an icon name from the icon array and the text to display beneath the button - for toggle buttons, additionally provide secondary colours, icon name and text. Also provide a reference to a global variable for the value of the button. The global variable should be declared at the start of the program and it may be adviable to use the 'status_name' format to ensure it is clear. - */ var joystickBtn = { primary_colour: 0x653E, @@ -200,18 +197,14 @@ var spkBtn = { }; /* - CONFIGURATION AREA - SCREEN DEFINITIONS - a screen can have a button (as defined above) on the left and/or the right of the screen. - in adddition a screen can optionally have an icon for each of the three buttons on the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. - */ const menuScreen = { left: autoBtn, @@ -234,11 +227,9 @@ const commsScreen = { }; /* base state definition - Each of the screens correspond to a state; this class provides a constuctor for each of the states - */ class State { constructor(params) { @@ -249,39 +240,28 @@ class State { } /* - CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS - This area defines how each screen behaves. - Each screen corresponds to a different State of the state machine. This makes it much easier to isolate behaviours between screens. - The state value is transmitted whenever a button is pressed to provide context (so the receiving device, knows which button was pressed on which screen). - The screens are defined above. - The events section identifies if a particular button has been pressed and released on the screen and an action can then be taken. - The events function receives a notification from a mySetWatch which provides an event object that identifies which button and whether it has been pressed down or released. Actions can then be taken. The events function will always return a State object. - If the events function returns different State from the current one, then the state machine will change to that new State and redrsw the screen appropriately. - To add in additional capabilities for button presses, simply add an additional 'if' statement. - For toggle buttons, the value of the sppropiate status object is inversed and the new value transmitted. - */ /* The Home State/Page is where the application beings */ @@ -352,19 +332,15 @@ const onOff= status => status ? "on" : "off"; /* create watching functions that will change the global button status when pressed or released - This is actuslly the hesrt of the program. When a button is not being pressed, nothing is happening (no loops). This makes the progrsm more battery efficient. - When a setWatch event is raised, the custom callbacks defined here will be called. These then fired as events to the current state/screen of the state mschine. - Some events, will result in the stste of the state machine chsnging, which is why the screen is redrswn after each button press. - */ const setMyWatch = (params) => { setWatch(() => { @@ -378,7 +354,7 @@ const setMyWatch = (params) => { */ const buttons = [ {bool : bottom_btn, label : "bottom",btn : BTN3}, - {bool : middle_btn, label : "mdiddle",btn : BTN2}, + {bool : middle_btn, label : "middle",btn : BTN2}, {bool : top_btn, label : "top",btn : BTN1}, {bool : left_btn, label : "left",btn : BTN4}, {bool : right_btn, label : "right",btn : BTN5} @@ -421,4 +397,4 @@ const drawScreen = (params) => { machine = Home; // instantiate the state machine at Home Bangle.drawWidgets(); // draw active widgets -drawScreen(machine.screen); // draw the screen +drawScreen(machine.screen); // draw the screen \ No newline at end of file From 42180a1770376ec1baeb37e433b902598b26784b Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Mon, 1 Jun 2020 00:46:27 +0100 Subject: [PATCH 17/48] New screens, buttons and icons --- apps/BLEcontroller/README.md | 30 ++- apps/BLEcontroller/app.js | 369 +++++++++++++++++++++++++++++++++-- 2 files changed, 381 insertions(+), 18 deletions(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 049a5f824..237392e1e 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -2,25 +2,43 @@ A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. Amaze your friends by controlling your robot from your watch! -Commands are sent from the Controller to the BLE robot in a JSON format. +To keep the messages small, commands are sent from the Controller to the BLE robot in a text string. This is made up of a comma delimited string of the following elements: +* message number (3 characters) +* screen name (3 characters) +* object name (3 characters) +* value/status (3 characters) + +The combination of these variables will uniquely identify the status change requested from the watch to the robot that can then be programmed to respond appropriately. ## Usage -The application can be configured at will by chaning the definitions of the screens, events, icons and buttons. +The application can be configured at will by changing the definitions of the screens, events, icons and buttons. Most changes are possible via data, rather than code change. ## Features -In its default state, it has three screens that provide the ability to: -turn the robot on or off -turn on and off its voice and microphone -make the robot move by spinning left or right and moving forward and backwards +In its default state, it has nine screens that provide the ability to: +* select which robot to interact with (dog or dalek) + * for the dog the following functions are available: + * control movement via a joystick (forwards, backwards, spin left, spin right) + * turn on/off follow mode + * start a game of chess + * wake or sleep the robot + * wag its tail in two directions + * for the dalek, the user can: + * turn on or off face recognition + * make it say random phrases + * control the dalek's iris light and servo + * turn the dalek hover lights on or off + * turn the speaker on or off ## Controls The controls will vary by screen, but I suggest a convention of using BTN3 (the bottom button) for moving backwards up the menu stack. +I have used the convention of red/green for buttons that are switches and blue buttons that provide single function operation (such as navigating a menu or executing a on-off activity) + ## Requests In the first instance, please consult my blog post on this application here. diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 3afae6b4b..6200600f1 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -80,11 +80,11 @@ const icons = [ }, { name: "left", - data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" }, { name: "right", - data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" }, { name: "forward", @@ -117,8 +117,60 @@ const icons = [ { name: "comms", data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + }, + { + name: "dalek", + data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" + }, + { + name: "k9", + data: "gEBAP4B/AP4B/AP4B/AP4B/AKAADIf5N/IaIAJJv5LZLeIARffZNdD5JN/KLYATC65RbAGrHlJ/5P/JuYrRJfovNJf4BdAFJL/Jv5N/Jv5L1Jv5PvJv5L7Jv5PpAGpN/dv5HzAP4B/AP4B/AP4B/AP4B/ALg" + }, + { + name: "pawn", + data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" + }, + { + name: "facerecog", + data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "wag_h", + data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" + }, + { + name: "wag_v", + data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" + }, + { + name: "happy", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" + }, + { + name: "sad", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" + }, + { + name: "hover", + data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" + }, + { + name: "light", + data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" + }, + { + name: "speak", + data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" } -]; + ]; /* finds icon data by name in the icon array and returns an image object*/ const drawIcon = (name) => { @@ -163,6 +215,114 @@ var turnRightBtn = { primary_icon: 'right', }; +var k9Btn = { + primary_colour: 0x653E, + primary_text: 'K9', + primary_icon: 'k9', + }; + +var dalekBtn = { + primary_colour: 0x33F9, + primary_text: 'Dalek', + primary_icon: 'dalek', + }; + +var tailHBtn = { + primary_colour: 0x653E, + primary_text: 'Wag Tail', + primary_icon: 'wag_h', + }; + +var tailVBtn = { + primary_colour: 0x33F9, + primary_text: 'Wag Tail', + primary_icon: 'wag_v', + }; + +var happyBtn = { + primary_colour: 0x653E, + primary_text: 'Speak', + primary_icon: 'happy', + }; + +var sadBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'sad', + }; + +var speakBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'speak', + }; + +var faceBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'facerecog', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'facerecog', + value: status_face + }; + +var chessBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'pawn', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'pawn', + value: status_chess + }; + +var irisLightBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'light', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'light', + value: status_iris_light + }; + +var irisBtn = { + primary_colour: 0xE9C7, + primary_text: 'Closed', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Open', + secondary_icon : 'awake', + value: status_iris + }; + +var wakeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Sleeping', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Awake', + secondary_icon : 'awake', + value: status_wake + }; + +var hoverBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'hover', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'hover', + value: status_hover + }; + var autoBtn = { primary_colour: 0xE9C7, primary_text: 'Stop', @@ -207,9 +367,16 @@ are defined as btn1, bt2 and bt3. The values are names from the icon array. */ const menuScreen = { - left: autoBtn, + left: k9Btn, + right: dalekBtn, +}; + +const k9MenuScreen = { + left: wakeBtn, right: joystickBtn, - btn1: "comms" + btn1: "pawn", + btn2: "wag_h", + btn3: "back" }; const joystickScreen = { @@ -220,12 +387,50 @@ const joystickScreen = { btn3: "back" }; +const tailScreen = { + left: tailHBtn, + right: tailVBtn, + btn3: "back" +}; + const commsScreen = { left: micBtn, right: spkBtn, btn3: "back" }; +const dalekMenuScreen = { + left: faceBtn, + right: speakBtn, + btn1: "hover", + btn2: "light", + btn3: "back" +}; + +const speakScreen = { + left: happyBtn, + right: sadBtn, + btn3: "back" +}; + +const irisScreen = { + left: irisBtn, + right: irisBirisLightBtn, + btn3: "back" +}; + +const lightsScreen = { + left: hoverBtn, + right: spkBtn, + btn3: "back" +}; + +const chessScreen = { + left: chessBtn, + right: autoBtn, + btn3: "back" +}; + /* base state definition Each of the screens correspond to a state; this class provides a constuctor for each @@ -270,15 +475,32 @@ const Home = new State({ screen: menuScreen, events: (event) => { if ((event.object == "right") && (event.status == "end")) { - transmit("Joystick", "joystick", "on"); - return Joystick; - } - if ((event.object == "top") && (event.status == "end")) { - return Comms; + return DalekMenu; } if ((event.object == "left") && (event.status == "end")) { - status_auto.value = !status_auto.value; - transmit(this.state, "auto", onOff(status_auto.value)); + //status_auto.value = !status_auto.value; + //transmit(this.state, "auto", onOff(status_auto.value)); + //return this; + return K9Menu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const K9Menu = new State({ + state: "K9Menu", + screen: k9MenuScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + return Joystick; + } + if ((event.object == "left") && (event.status == "end")) { + status_wake.value = !status_wake.value; + transmit(this.state, "auto", onOff(status_wake.value)); return this; } transmit(this.state, event.object, event.status); @@ -286,6 +508,129 @@ const Home = new State({ } }); +const DalekMenu = new State({ + state: "DalekMenu", + screen: dalekMenuScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + return Speak; + } + if ((event.object == "left") && (event.status == "end")) { + status_face.value = !status_face.value; + transmit(this.state, "face", onOff(status_face.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Speak = new State({ + state: "Speak", + screen: speakScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return DalekMenu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Chess = new State({ + state: "Chess", + screen: chessScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return K9Menu; + } + if ((event.object == "right") && (event.status == "end")) { + status_auto.value = !status_auto.value; + transmit(this.state, "follow", onOff(status_auto.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_chess.value = !status_chess.value; + transmit(this.state, "chess", onOff(status_chess.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Tail = new State({ + state: "Tail", + screen: tailScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return K9Menu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Speak = new State({ + state: "Speak", + screen: speakScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return DalekMenu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Iris = new State({ + state: "Iris", + screen: irisScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return DalekMenu; + } + if ((event.object == "right") && (event.status == "end")) { + status_iris_light.value = !status_iris_light.value; + transmit(this.state, "iris_light", onOff(status_iris_light.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_iris.value = !status_iris.value; + transmit(this.state, "iris_servo", onOff(status_iris.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Lights = new State({ + state: "Lights", + screen: lightsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return DalekMenu; + } + if ((event.object == "right") && (event.status == "end")) { + status_spk.value = !status_spk.value; + transmit(this.state, "iris_light", onOff(status_spk.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_hover.value = !status_hover.value; + transmit(this.state, "hover", onOff(status_hover.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + + /* Joystick page state */ const Joystick = new State({ state: "Joystick", From 5bc70b474c0121bc26e7efdf4be07d6a3f876a4f Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 10:42:57 +0100 Subject: [PATCH 18/48] Merge didn't; t work --- apps.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 883a3cdf9..d266cd0c0 100644 --- a/apps.json +++ b/apps.json @@ -1768,11 +1768,10 @@ "storage": [ { "name": "jbm8b.app.js", "url": "app.js" }, { "name": "jbm8b.img", "url": "app-icon.js", "evaluate": true } - ], + ] "version": "0.03" }, -{ - "id": "BLEcontroller", + { "id": "BLEcontroller", "name": "BLE Robot Controller with Joystick", "shortName": "BLE Controller", "icon": "BLEcontroller.png", @@ -1784,6 +1783,8 @@ "storage": [ { "name": "BLEcontroller.app.js", "url": "app.js" }, { "name": "BLEcontroller.img", "url": "app-icon.js", "evaluate": true } + ] + }, { "id": "widviz", "name": "Widget Visibility Widget", "shortName":"Viz Widget", From 6aad4d8f93413c30c3d6b579040920a2c87124b8 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 11:27:51 +0100 Subject: [PATCH 19/48] Fixing JSON --- apps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index d266cd0c0..6c0f50eca 100644 --- a/apps.json +++ b/apps.json @@ -1765,11 +1765,11 @@ "icon": "app.png", "description": "A simple fortune telling app", "tags": "game", + "version": "0.03", "storage": [ { "name": "jbm8b.app.js", "url": "app.js" }, { "name": "jbm8b.img", "url": "app-icon.js", "evaluate": true } - ] - "version": "0.03" + ] }, { "id": "BLEcontroller", "name": "BLE Robot Controller with Joystick", From 26d0fd32792b755c012223a982bf6b8b54b43dd1 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 11:40:59 +0100 Subject: [PATCH 20/48] Adding variable declarations and syntax error --- apps/BLEcontroller/app.js | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 6200600f1..7ba95589d 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -1,6 +1,6 @@ /* ========================================================== -Simple event based robot controller that enables robot +Simple event based robot controller that enables robot to switch into automatic or manual control modes. Behaviours are controlled via a simple finite state machine. In automatic mode the @@ -19,7 +19,7 @@ bottom_btn = false; msgNum = 0; // message number -/* +/* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button statuses; if you add an additional toggle button @@ -28,6 +28,12 @@ you should declare it and initiase it here */ var status_auto = {value: false}; var status_mic = {value: true}; var status_spk = {value: true}; +var status_face = {value: true}; +var status_chess = {value: false}; +var status_iris_light = {value: false}; +var status_iris = {value: false}; +var status_wake = {value: false}; +var status_hover = {value: false}; /* trsnsmit message where @@ -415,7 +421,7 @@ const speakScreen = { const irisScreen = { left: irisBtn, - right: irisBirisLightBtn, + right: irisLightBtn, btn3: "back" }; @@ -431,9 +437,9 @@ const chessScreen = { btn3: "back" }; -/* base state definition +/* base state definition Each of the screens correspond to a state; -this class provides a constuctor for each +this class provides a constuctor for each of the states */ class State { @@ -605,7 +611,7 @@ const Iris = new State({ } transmit(this.state, event.object, event.status); return this; - } + } }); const Lights = new State({ @@ -627,7 +633,7 @@ const Lights = new State({ } transmit(this.state, event.object, event.status); return this; - } + } }); @@ -676,7 +682,7 @@ const onOff= status => status ? "on" : "off"; /* create watching functions that will change the global -button status when pressed or released +button status when pressed or released This is actuslly the hesrt of the program. When a button is not being pressed, nothing is happening (no loops). This makes the progrsm more battery efficient. @@ -684,7 +690,7 @@ When a setWatch event is raised, the custom callbacks defined here will be called. These then fired as events to the current state/screen of the state mschine. Some events, will result in the stste of the state machine -chsnging, which is why the screen is redrswn after each +chsnging, which is why the screen is redrswn after each button press. */ const setMyWatch = (params) => { @@ -742,4 +748,4 @@ const drawScreen = (params) => { machine = Home; // instantiate the state machine at Home Bangle.drawWidgets(); // draw active widgets -drawScreen(machine.screen); // draw the screen \ No newline at end of file +drawScreen(machine.screen); // draw the screen From a5cc710ef84f053b598fad8eb0c2e3834140d1c9 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 11:44:27 +0100 Subject: [PATCH 21/48] Syntax error --- apps/BLEcontroller/app.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 7ba95589d..2ad91ba54 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -580,18 +580,6 @@ const Tail = new State({ } }); -const Speak = new State({ - state: "Speak", - screen: speakScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return DalekMenu; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - const Iris = new State({ state: "Iris", screen: irisScreen, From b929b5d0cbe903070f741510f4681e23333e3951 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 14:19:23 +0100 Subject: [PATCH 22/48] Splitting app into three variants --- apps/BLEcontroller/README.md | 32 +- apps/BLEcontroller/app-big.js | 739 ++++++++++++++++++++++++++++++++++ apps/BLEcontroller/app.js | 520 ++++-------------------- 3 files changed, 824 insertions(+), 467 deletions(-) create mode 100644 apps/BLEcontroller/app-big.js diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 237392e1e..56f1a2658 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -1,14 +1,18 @@ -# BLE Robot Controller with Joystick +# BLE Generic Controller with Joystick -A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. Amaze your friends by controlling your robot from your watch! +A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. -To keep the messages small, commands are sent from the Controller to the BLE robot in a text string. This is made up of a comma delimited string of the following elements: +Amaze your friends by controlling your robot, your house or any other BLE device from your watch! + +To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: * message number (3 characters) * screen name (3 characters) * object name (3 characters) * value/status (3 characters) -The combination of these variables will uniquely identify the status change requested from the watch to the robot that can then be programmed to respond appropriately. +The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. + +Gordon Williams' EspruinoHub is an excellent way to transform BLE advertisements into MQTT messages for further processing. ## Usage @@ -18,20 +22,12 @@ Most changes are possible via data, rather than code change. ## Features -In its default state, it has nine screens that provide the ability to: -* select which robot to interact with (dog or dalek) - * for the dog the following functions are available: - * control movement via a joystick (forwards, backwards, spin left, spin right) - * turn on/off follow mode - * start a game of chess - * wake or sleep the robot - * wag its tail in two directions - * for the dalek, the user can: - * turn on or off face recognition - * make it say random phrases - * control the dalek's iris light and servo - * turn the dalek hover lights on or off - * turn the speaker on or off +The default package contains three configurations: +* a simple home light and sockets controller UI (app.js) +* a robot controller UI with joystick (app-joy.js) +* a simple static assistant controller (app-ass.js) + +You can try out the other configurations by deleting app.js and renaming the file you want to app.js. ## Controls diff --git a/apps/BLEcontroller/app-big.js b/apps/BLEcontroller/app-big.js new file mode 100644 index 000000000..2ad91ba54 --- /dev/null +++ b/apps/BLEcontroller/app-big.js @@ -0,0 +1,739 @@ +/* +========================================================== +Simple event based robot controller that enables robot +to switch into automatic or manual control modes. Behaviours +are controlled via a simple finite state machine. +In automatic mode the +robot will look after itself. In manual mode, the watch +will provide simple forward, back, left and right commands. +The messages will be transmitted to a partner BLE Espruino +using BLE +Written by Richard Hopkins, May 2020 +========================================================== +declare global variables for watch button statuses */ +top_btn = false; +middle_btn = false; +left_btn= false; // the left side of the touch screen +right_btn = false; // the right side of the touch screen +bottom_btn = false; + +msgNum = 0; // message number + +/* +CONFIGURATION AREA - STATE VARIABLES +declare global variables for the toggle button +statuses; if you add an additional toggle button +you should declare it and initiase it here */ + +var status_auto = {value: false}; +var status_mic = {value: true}; +var status_spk = {value: true}; +var status_face = {value: true}; +var status_chess = {value: false}; +var status_iris_light = {value: false}; +var status_iris = {value: false}; +var status_wake = {value: false}; +var status_hover = {value: false}; + +/* trsnsmit message +where +s = first character of state, +o = first three character of object name +v = value of state.object +*/ + +const transmit = (state,object,status) => { + msgNum ++; + msg = { + n: msgNum.toString().slice(-4), + s: state.substr(0,4), + o: object.substr(0,4), + v: status.substr(0.4), + }; + message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; + NRF.setAdvertising({},{ + showName: false, + manufacturer: 0x0590, + manufacturerData: JSON.stringify(message)}); +}; + +/* +CONFIGURATION AREA - ICON DEFINITIONS +Retrieve 30px PNG icons from: +https://icons8.com/icon/set/speak/ios-glyphs +Create icons using: +https://www.espruino.com/Image+Converter +Use compression: true +Transparency: true +Diffusion: flat +Colours: 16bit RGB +Ouput as: Image Object +Add an additional element to the icons array +with a unique name and the data from the Image Object +*/ +const icons = [ + { + name: "walk", + data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" + }, + { + name: "sit", + data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" + }, + { + name: "joystick", + data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" + }, + { + name: "left", + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + }, + { + name: "right", + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + }, + { + name: "forward", + data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" + }, + { + name: "backward", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" + }, + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "spk_on", + data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" + }, + { + name: "spk_off", + data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" + }, + { + name: "mic_on", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" + }, + { + name: "mic_off", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Wf47/HJZLjHZ45RHrI7NHJYhLHqoZJA54hNHr5lTXL6vPSra5jKbo9REZrLRHa5DTXp47jAA7TTF7INLRqY7fdKavhXKo5te6wA==" + }, + { + name: "comms", + data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + }, + { + name: "dalek", + data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" + }, + { + name: "k9", + data: "gEBAP4B/AP4B/AP4B/AP4B/AKAADIf5N/IaIAJJv5LZLeIARffZNdD5JN/KLYATC65RbAGrHlJ/5P/JuYrRJfovNJf4BdAFJL/Jv5N/Jv5L1Jv5PvJv5L7Jv5PpAGpN/dv5HzAP4B/AP4B/AP4B/AP4B/ALg" + }, + { + name: "pawn", + data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" + }, + { + name: "facerecog", + data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "wag_h", + data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" + }, + { + name: "wag_v", + data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" + }, + { + name: "happy", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" + }, + { + name: "sad", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" + }, + { + name: "hover", + data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" + }, + { + name: "light", + data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" + }, + { + name: "speak", + data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" + } + ]; + +/* finds icon data by name in the icon array and returns an image object*/ +const drawIcon = (name) => { + for (var icon of icons) { + if (icon.name == name) { + image = { + width : 30, height : 30, bpp : 16, + transparent : 1, + buffer: require("heatshrink").decompress(atob(icon.data)) + }; + return image;} + } +}; + +/* +CONFIGURATION AREA - BUTTON DEFINITIONS +for a simple button, just define a primary colour +and an icon name from the icon array and +the text to display beneath the button +for toggle buttons, additionally provide secondary +colours, icon name and text. Also provide a reference +to a global variable for the value of the button. +The global variable should be declared at the start of +the program and it may be adviable to use the 'status_name' +format to ensure it is clear. +*/ +var joystickBtn = { + primary_colour: 0x653E, + primary_icon: 'joystick', + primary_text: 'Joystick', + }; + +var turnLeftBtn = { + primary_colour: 0x653E, + primary_text: 'Left', + primary_icon: 'left', + }; + +var turnRightBtn = { + primary_colour: 0x33F9, + primary_text: 'Right', + primary_icon: 'right', + }; + +var k9Btn = { + primary_colour: 0x653E, + primary_text: 'K9', + primary_icon: 'k9', + }; + +var dalekBtn = { + primary_colour: 0x33F9, + primary_text: 'Dalek', + primary_icon: 'dalek', + }; + +var tailHBtn = { + primary_colour: 0x653E, + primary_text: 'Wag Tail', + primary_icon: 'wag_h', + }; + +var tailVBtn = { + primary_colour: 0x33F9, + primary_text: 'Wag Tail', + primary_icon: 'wag_v', + }; + +var happyBtn = { + primary_colour: 0x653E, + primary_text: 'Speak', + primary_icon: 'happy', + }; + +var sadBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'sad', + }; + +var speakBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'speak', + }; + +var faceBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'facerecog', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'facerecog', + value: status_face + }; + +var chessBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'pawn', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'pawn', + value: status_chess + }; + +var irisLightBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'light', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'light', + value: status_iris_light + }; + +var irisBtn = { + primary_colour: 0xE9C7, + primary_text: 'Closed', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Open', + secondary_icon : 'awake', + value: status_iris + }; + +var wakeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Sleeping', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Awake', + secondary_icon : 'awake', + value: status_wake + }; + +var hoverBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'hover', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'hover', + value: status_hover + }; + +var autoBtn = { + primary_colour: 0xE9C7, + primary_text: 'Stop', + primary_icon: 'sit', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Move', + secondary_icon : 'walk', + value: status_auto + }; + +var micBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'mic_off', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'mic_on', + value: status_mic + }; + +var spkBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'spk_off', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'spk_on', + value: status_spk + }; + +/* +CONFIGURATION AREA - SCREEN DEFINITIONS +a screen can have a button (as defined above) +on the left and/or the right of the screen. +in adddition a screen can optionally have +an icon for each of the three buttons on +the left hand side of the screen. These +are defined as btn1, bt2 and bt3. The +values are names from the icon array. +*/ +const menuScreen = { + left: k9Btn, + right: dalekBtn, +}; + +const k9MenuScreen = { + left: wakeBtn, + right: joystickBtn, + btn1: "pawn", + btn2: "wag_h", + btn3: "back" +}; + +const joystickScreen = { + left: turnLeftBtn, + right: turnRightBtn, + btn1: "forward", + btn2: "backward", + btn3: "back" +}; + +const tailScreen = { + left: tailHBtn, + right: tailVBtn, + btn3: "back" +}; + +const commsScreen = { + left: micBtn, + right: spkBtn, + btn3: "back" +}; + +const dalekMenuScreen = { + left: faceBtn, + right: speakBtn, + btn1: "hover", + btn2: "light", + btn3: "back" +}; + +const speakScreen = { + left: happyBtn, + right: sadBtn, + btn3: "back" +}; + +const irisScreen = { + left: irisBtn, + right: irisLightBtn, + btn3: "back" +}; + +const lightsScreen = { + left: hoverBtn, + right: spkBtn, + btn3: "back" +}; + +const chessScreen = { + left: chessBtn, + right: autoBtn, + btn3: "back" +}; + +/* base state definition +Each of the screens correspond to a state; +this class provides a constuctor for each +of the states +*/ +class State { + constructor(params) { + this.state = params.state; + this.events = params.events; + this.screen = params.screen; + } +} + +/* +CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS +This area defines how each screen behaves. +Each screen corresponds to a different State of the +state machine. This makes it much easier to isolate +behaviours between screens. +The state value is transmitted whenever a button is pressed +to provide context (so the receiving device, knows which +button was pressed on which screen). +The screens are defined above. +The events section identifies if a particular button has been +pressed and released on the screen and an action can then be taken. +The events function receives a notification from a mySetWatch which +provides an event object that identifies which button and whether +it has been pressed down or released. Actions can then be taken. +The events function will always return a State object. +If the events function returns different State from the current +one, then the state machine will change to that new State and redrsw +the screen appropriately. +To add in additional capabilities for button presses, simply add +an additional 'if' statement. +For toggle buttons, the value of the sppropiate status object is +inversed and the new value transmitted. +*/ + +/* The Home State/Page is where the application beings */ +const Home = new State({ + state: "Home", + screen: menuScreen, + events: (event) => { + if ((event.object == "right") && (event.status == "end")) { + return DalekMenu; + } + if ((event.object == "left") && (event.status == "end")) { + //status_auto.value = !status_auto.value; + //transmit(this.state, "auto", onOff(status_auto.value)); + //return this; + return K9Menu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const K9Menu = new State({ + state: "K9Menu", + screen: k9MenuScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + return Joystick; + } + if ((event.object == "left") && (event.status == "end")) { + status_wake.value = !status_wake.value; + transmit(this.state, "auto", onOff(status_wake.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const DalekMenu = new State({ + state: "DalekMenu", + screen: dalekMenuScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + return Speak; + } + if ((event.object == "left") && (event.status == "end")) { + status_face.value = !status_face.value; + transmit(this.state, "face", onOff(status_face.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Speak = new State({ + state: "Speak", + screen: speakScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return DalekMenu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Chess = new State({ + state: "Chess", + screen: chessScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return K9Menu; + } + if ((event.object == "right") && (event.status == "end")) { + status_auto.value = !status_auto.value; + transmit(this.state, "follow", onOff(status_auto.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_chess.value = !status_chess.value; + transmit(this.state, "chess", onOff(status_chess.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Tail = new State({ + state: "Tail", + screen: tailScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return K9Menu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Iris = new State({ + state: "Iris", + screen: irisScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return DalekMenu; + } + if ((event.object == "right") && (event.status == "end")) { + status_iris_light.value = !status_iris_light.value; + transmit(this.state, "iris_light", onOff(status_iris_light.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_iris.value = !status_iris.value; + transmit(this.state, "iris_servo", onOff(status_iris.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Lights = new State({ + state: "Lights", + screen: lightsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return DalekMenu; + } + if ((event.object == "right") && (event.status == "end")) { + status_spk.value = !status_spk.value; + transmit(this.state, "iris_light", onOff(status_spk.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_hover.value = !status_hover.value; + transmit(this.state, "hover", onOff(status_hover.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + + +/* Joystick page state */ +const Joystick = new State({ + state: "Joystick", + screen: joystickScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + transmit("Joystick", "joystick", "off"); + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* Comms page state */ +const Comms = new State({ + state: "Comms", + screen: commsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "left") && (event.status == "end")) { + status_mic.value = !status_mic.value; + transmit(this.state, "mic", onOff(status_mic.value)); + return this; + } + if ((event.object == "right") && (event.status == "end")) { + status_spk.value = !status_spk.value; + transmit(this.state, "spk", onOff(status_spk.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* translate button status into english */ +const startEnd = status => status ? "start" : "end"; + +/* translate status into english */ +const onOff= status => status ? "on" : "off"; + + +/* create watching functions that will change the global +button status when pressed or released +This is actuslly the hesrt of the program. When a button +is not being pressed, nothing is happening (no loops). +This makes the progrsm more battery efficient. +When a setWatch event is raised, the custom callbacks defined +here will be called. These then fired as events to the current +state/screen of the state mschine. +Some events, will result in the stste of the state machine +chsnging, which is why the screen is redrswn after each +button press. +*/ +const setMyWatch = (params) => { + setWatch(() => { + params.bool=!params.bool; + machine = machine.events({object: params.label, status: startEnd(params.bool)}); + drawScreen(machine.screen); + }, params.btn, {repeat:true, edge:"both"}); +}; + +/* object array used to set up the watching functions +*/ +const buttons = [ + {bool : bottom_btn, label : "bottom",btn : BTN3}, + {bool : middle_btn, label : "middle",btn : BTN2}, + {bool : top_btn, label : "top",btn : BTN1}, + {bool : left_btn, label : "left",btn : BTN4}, + {bool : right_btn, label : "right",btn : BTN5} + ]; + +/* set up watchers for buttons */ +for (var button of buttons) + {setMyWatch(button);} + +/* Draw various kinds of buttons */ +const drawButton = (params,side) => { + g.setFontAlign(0,1); + icon = drawIcon(params.primary_icon); + text = params.primary_text; + g.setColor(params.primary_colour); + const x = (side == "left") ? 0 : 120; + if ((params.toggle) && (params.value.value)) { + g.setColor(params.secondary_colour); + text = params.secondary_text; + icon = drawIcon(params.secondary_icon); + } + g.fillRect(0+x,24,119+x, 239); + g.setColor(0x000); + g.setFont("Vector",15); + g.setFontAlign(0,0.0); + g.drawString(text,60+x,160); + options = {rotate: 0, scale:2}; + g.drawImage(icon,x+60,120,options); +}; + +/* Draw the pages corresponding to the states */ +const drawScreen = (params) => { + drawButton(params.left,'left'); + drawButton(params.right,'right'); + g.setColor(0x000); + if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} + if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} + if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} +}; + +machine = Home; // instantiate the state machine at Home +Bangle.drawWidgets(); // draw active widgets +drawScreen(machine.screen); // draw the screen diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 2ad91ba54..1b4775ef2 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -25,15 +25,10 @@ declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_auto = {value: false}; -var status_mic = {value: true}; -var status_spk = {value: true}; -var status_face = {value: true}; -var status_chess = {value: false}; -var status_iris_light = {value: false}; -var status_iris = {value: false}; -var status_wake = {value: false}; -var status_hover = {value: false}; +var status_printer = {value: false}; +var status_tv = {value: false}; +var status_light_hall = {value: false}; +var status_light_study = {value: false}; /* trsnsmit message where @@ -73,108 +68,12 @@ with a unique name and the data from the Image Object */ const icons = [ { - name: "walk", - data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" - }, - { - name: "sit", - data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" - }, - { - name: "joystick", - data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" - }, - { - name: "left", - data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" - }, - { - name: "right", - data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" - }, - { - name: "forward", - data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" - }, - { - name: "backward", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" - }, - { - name: "back", - data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" - }, - { - name: "spk_on", - data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" - }, - { - name: "spk_off", - data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" - }, - { - name: "mic_on", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" - }, - { - name: "mic_off", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Wf47/HJZLjHZ45RHrI7NHJYhLHqoZJA54hNHr5lTXL6vPSra5jKbo9REZrLRHa5DTXp47jAA7TTF7INLRqY7fdKavhXKo5te6wA==" - }, - { - name: "comms", - data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" - }, - { - name: "dalek", - data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" - }, - { - name: "k9", - data: "gEBAP4B/AP4B/AP4B/AP4B/AKAADIf5N/IaIAJJv5LZLeIARffZNdD5JN/KLYATC65RbAGrHlJ/5P/JuYrRJfovNJf4BdAFJL/Jv5N/Jv5L1Jv5PvJv5L7Jv5PpAGpN/dv5HzAP4B/AP4B/AP4B/AP4B/ALg" - }, - { - name: "pawn", - data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" - }, - { - name: "facerecog", - data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" - }, - { - name: "sleep", - data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" - }, - { - name: "awake", - data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" - }, - { - name: "wag_h", - data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" - }, - { - name: "wag_v", - data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" - }, - { - name: "happy", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" - }, - { - name: "sad", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" - }, - { - name: "hover", - data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" + name: "switch", + data: "gEBAP4B/AP4B/AP4B/AMgA3HPJdlVvI7/Hf47/Hf47/Hf47/Hf47/Hf4AvIPKRXAP4B/AP4B/AP4B/AJgA==" }, { name: "light", data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" - }, - { - name: "speak", - data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" } ]; @@ -203,164 +102,62 @@ The global variable should be declared at the start of the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var joystickBtn = { + +var lightBtn = { primary_colour: 0x653E, - primary_icon: 'joystick', - primary_text: 'Joystick', + primary_text: 'Lights', + primary_icon: 'light', }; -var turnLeftBtn = { - primary_colour: 0x653E, - primary_text: 'Left', - primary_icon: 'left', - }; - -var turnRightBtn = { +var socketsBtn = { primary_colour: 0x33F9, - primary_text: 'Right', - primary_icon: 'right', + primary_text: 'Sockets', + primary_icon: 'switch', }; -var k9Btn = { - primary_colour: 0x653E, - primary_text: 'K9', - primary_icon: 'k9', - }; - -var dalekBtn = { - primary_colour: 0x33F9, - primary_text: 'Dalek', - primary_icon: 'dalek', - }; - -var tailHBtn = { - primary_colour: 0x653E, - primary_text: 'Wag Tail', - primary_icon: 'wag_h', - }; - -var tailVBtn = { - primary_colour: 0x33F9, - primary_text: 'Wag Tail', - primary_icon: 'wag_v', - }; - -var happyBtn = { - primary_colour: 0x653E, - primary_text: 'Speak', - primary_icon: 'happy', - }; - -var sadBtn = { - primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'sad', - }; - -var speakBtn = { - primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'speak', - }; - -var faceBtn = { +var lightHallBtn = { primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'facerecog', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'facerecog', - value: status_face - }; - -var chessBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'pawn', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'pawn', - value: status_chess - }; - -var irisLightBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', + primary_text: 'Hall Off', primary_icon: 'light', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'On', + secondary_text: 'Hall On', secondary_icon : 'light', - value: status_iris_light + value: status_light_hall }; -var irisBtn = { +var lightStudyBtn = { primary_colour: 0xE9C7, - primary_text: 'Closed', - primary_icon: 'sleep', + primary_text: 'Study Off', + primary_icon: 'light', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Open', - secondary_icon : 'awake', - value: status_iris + secondary_text: 'Study On', + secondary_icon : 'light', + value: status_light_study +}; + +var socketTVBtn = { + primary_colour: 0xE9C7, + primary_text: 'TV Off', + primary_icon: 'switch', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'TV On', + secondary_icon : 'switch', + value: status_tv }; -var wakeBtn = { +var socketPrinterBtn = { primary_colour: 0xE9C7, - primary_text: 'Sleeping', - primary_icon: 'sleep', + primary_text: 'Printer Off', + primary_icon: 'switch', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Awake', - secondary_icon : 'awake', - value: status_wake - }; - -var hoverBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'hover', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'hover', - value: status_hover - }; - -var autoBtn = { - primary_colour: 0xE9C7, - primary_text: 'Stop', - primary_icon: 'sit', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Move', - secondary_icon : 'walk', - value: status_auto - }; - -var micBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'mic_off', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'mic_on', - value: status_mic - }; - -var spkBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'spk_off', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'spk_on', - value: status_spk - }; + secondary_text: 'Printer On', + secondary_icon : 'switch', + value: status_printer +}; /* CONFIGURATION AREA - SCREEN DEFINITIONS @@ -372,68 +169,20 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ -const menuScreen = { - left: k9Btn, - right: dalekBtn, -}; - -const k9MenuScreen = { - left: wakeBtn, - right: joystickBtn, - btn1: "pawn", - btn2: "wag_h", - btn3: "back" -}; - -const joystickScreen = { - left: turnLeftBtn, - right: turnRightBtn, - btn1: "forward", - btn2: "backward", - btn3: "back" -}; - -const tailScreen = { - left: tailHBtn, - right: tailVBtn, - btn3: "back" -}; - -const commsScreen = { - left: micBtn, - right: spkBtn, - btn3: "back" -}; - -const dalekMenuScreen = { - left: faceBtn, - right: speakBtn, - btn1: "hover", - btn2: "light", - btn3: "back" -}; - -const speakScreen = { - left: happyBtn, - right: sadBtn, - btn3: "back" -}; - -const irisScreen = { - left: irisBtn, - right: irisLightBtn, - btn3: "back" +const homeScreen = { + left: lightsBtn, + right: socketsBtn, }; const lightsScreen = { - left: hoverBtn, - right: spkBtn, + left: lightHallBtn, + right: lightStudyBtn, btn3: "back" }; -const chessScreen = { - left: chessBtn, - right: autoBtn, +const socketsScreen = { + left: socketTVBtn, + right: socketPrinterBtn, btn3: "back" }; @@ -478,145 +227,34 @@ inversed and the new value transmitted. /* The Home State/Page is where the application beings */ const Home = new State({ state: "Home", - screen: menuScreen, + screen: homeScreen, events: (event) => { if ((event.object == "right") && (event.status == "end")) { - return DalekMenu; + return SocketsMenu; } if ((event.object == "left") && (event.status == "end")) { - //status_auto.value = !status_auto.value; - //transmit(this.state, "auto", onOff(status_auto.value)); - //return this; - return K9Menu; + return LightsMenu; } transmit(this.state, event.object, event.status); return this; } }); -const K9Menu = new State({ - state: "K9Menu", - screen: k9MenuScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - return Joystick; - } - if ((event.object == "left") && (event.status == "end")) { - status_wake.value = !status_wake.value; - transmit(this.state, "auto", onOff(status_wake.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const DalekMenu = new State({ - state: "DalekMenu", - screen: dalekMenuScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - return Speak; - } - if ((event.object == "left") && (event.status == "end")) { - status_face.value = !status_face.value; - transmit(this.state, "face", onOff(status_face.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Speak = new State({ - state: "Speak", - screen: speakScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return DalekMenu; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Chess = new State({ - state: "Chess", - screen: chessScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return K9Menu; - } - if ((event.object == "right") && (event.status == "end")) { - status_auto.value = !status_auto.value; - transmit(this.state, "follow", onOff(status_auto.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_chess.value = !status_chess.value; - transmit(this.state, "chess", onOff(status_chess.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Tail = new State({ - state: "Tail", - screen: tailScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return K9Menu; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Iris = new State({ - state: "Iris", - screen: irisScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return DalekMenu; - } - if ((event.object == "right") && (event.status == "end")) { - status_iris_light.value = !status_iris_light.value; - transmit(this.state, "iris_light", onOff(status_iris_light.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_iris.value = !status_iris.value; - transmit(this.state, "iris_servo", onOff(status_iris.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Lights = new State({ - state: "Lights", +const LightsMenu = new State({ + state: "LightsMenu", screen: lightsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { - return DalekMenu; + return Home; } if ((event.object == "right") && (event.status == "end")) { - status_spk.value = !status_spk.value; - transmit(this.state, "iris_light", onOff(status_spk.value)); + status_light_study.value = !status_light_study.value; + transmit(this.state, "auto", onOff(status_light_study.value)); return this; } if ((event.object == "left") && (event.status == "end")) { - status_hover.value = !status_hover.value; - transmit(this.state, "hover", onOff(status_hover.value)); + status_light_hall.value = !status_light_hall.value; + transmit(this.state, "auto", onOff(status_light_hall.value)); return this; } transmit(this.state, event.object, event.status); @@ -624,42 +262,26 @@ const Lights = new State({ } }); - -/* Joystick page state */ -const Joystick = new State({ - state: "Joystick", - screen: joystickScreen, +const SocketsMenu = new State({ + state: "SocketsMenu", + screen: lightsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { - transmit("Joystick", "joystick", "off"); - return Home; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -/* Comms page state */ -const Comms = new State({ - state: "Comms", - screen: commsScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "left") && (event.status == "end")) { - status_mic.value = !status_mic.value; - transmit(this.state, "mic", onOff(status_mic.value)); - return this; + return Home; } if ((event.object == "right") && (event.status == "end")) { - status_spk.value = !status_spk.value; - transmit(this.state, "spk", onOff(status_spk.value)); + status_printer.value = !status_printer.value; + transmit(this.state, "auto", onOff(status_printer.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_tv.value = !status_tv.value; + transmit(this.state, "auto", onOff(status_tv.value)); return this; } transmit(this.state, event.object, event.status); return this; - } + } }); /* translate button status into english */ From 0b7200eda7a444030ea02124486fc3a5214e34f6 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 14:20:46 +0100 Subject: [PATCH 23/48] Minor README change --- apps/BLEcontroller/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 56f1a2658..0929a9fd7 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -1,4 +1,4 @@ -# BLE Generic Controller with Joystick +# BLE Customisable Controller with Joystick A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. From 60b0fee49d230554b5c09a0e870173b194ec0b61 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 14:22:38 +0100 Subject: [PATCH 24/48] Change to app description --- apps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 9ba610101..79923cab2 100644 --- a/apps.json +++ b/apps.json @@ -1772,11 +1772,11 @@ ] }, { "id": "BLEcontroller", - "name": "BLE Robot Controller with Joystick", + "name": "BLE Customisable Controller with Joystick", "shortName": "BLE Controller", "icon": "BLEcontroller.png", "version": "0.01", - "description": "A configurable controller for BLE robots, with a basic four direction joystick. Easy to customise and add your own menus.", + "description": "A configurable controller for BLE devices and robots, with a basic four direction joystick. Designed to be easy to customise so you can add your own menus.", "tags": "tool,bluetooth", "readme": "README.md", "allow_emulator":true, From 03f4f1da8bca0474b371e8bb68728479faf4d09c Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 14:27:02 +0100 Subject: [PATCH 25/48] Bug fix --- apps/BLEcontroller/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 1b4775ef2..96f56efce 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -170,7 +170,7 @@ are defined as btn1, bt2 and bt3. The values are names from the icon array. */ const homeScreen = { - left: lightsBtn, + left: lightBtn, right: socketsBtn, }; From b9f0907e5a1a371038f56e5a57a5d69b015bbc02 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 14:36:03 +0100 Subject: [PATCH 26/48] Added back icon --- apps/BLEcontroller/README.md | 2 +- apps/BLEcontroller/app.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 0929a9fd7..d66ea9557 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -1,4 +1,4 @@ -# BLE Customisable Controller with Joystick +# BLE Customisable Controller with Joystick A A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 96f56efce..0ae900b9b 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -74,6 +74,10 @@ const icons = [ { name: "light", data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" + }, + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" } ]; @@ -220,7 +224,7 @@ one, then the state machine will change to that new State and redrsw the screen appropriately. To add in additional capabilities for button presses, simply add an additional 'if' statement. -For toggle buttons, the value of the sppropiate status object is +For toggle buttons, the value of the appropiate status object is inversed and the new value transmitted. */ From 9f1b61d2d9211fed78e5e405023d46fbbfcee876 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 14:41:52 +0100 Subject: [PATCH 27/48] Minor bug fix --- apps/BLEcontroller/README.md | 2 +- apps/BLEcontroller/app.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index d66ea9557..0929a9fd7 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -1,4 +1,4 @@ -# BLE Customisable Controller with Joystick A +# BLE Customisable Controller with Joystick A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 0ae900b9b..fc7d7dbb7 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -268,7 +268,7 @@ const LightsMenu = new State({ const SocketsMenu = new State({ state: "SocketsMenu", - screen: lightsScreen, + screen: socketsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; From 615f8c8fcefc3a1d71c5f63b3be1f0659fb16e56 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 15:18:48 +0100 Subject: [PATCH 28/48] Update transmitted values --- apps/BLEcontroller/app.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index fc7d7dbb7..fd07d73f9 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -253,12 +253,12 @@ const LightsMenu = new State({ } if ((event.object == "right") && (event.status == "end")) { status_light_study.value = !status_light_study.value; - transmit(this.state, "auto", onOff(status_light_study.value)); + transmit(this.state, "study", onOff(status_light_study.value)); return this; } if ((event.object == "left") && (event.status == "end")) { status_light_hall.value = !status_light_hall.value; - transmit(this.state, "auto", onOff(status_light_hall.value)); + transmit(this.state, "hall", onOff(status_light_hall.value)); return this; } transmit(this.state, event.object, event.status); @@ -275,12 +275,12 @@ const SocketsMenu = new State({ } if ((event.object == "right") && (event.status == "end")) { status_printer.value = !status_printer.value; - transmit(this.state, "auto", onOff(status_printer.value)); + transmit(this.state, "printer", onOff(status_printer.value)); return this; } if ((event.object == "left") && (event.status == "end")) { status_tv.value = !status_tv.value; - transmit(this.state, "auto", onOff(status_tv.value)); + transmit(this.state, "tv", onOff(status_tv.value)); return this; } transmit(this.state, event.object, event.status); From 7cf0154259994b84a9dd5944b8bb8eb42d7c258d Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 15:21:08 +0100 Subject: [PATCH 29/48] Adding widgets back in --- apps/BLEcontroller/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index fd07d73f9..3f18ffa1c 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -313,6 +313,7 @@ const setMyWatch = (params) => { machine = machine.events({object: params.label, status: startEnd(params.bool)}); drawScreen(machine.screen); }, params.btn, {repeat:true, edge:"both"}); + drawWidgets(); }; /* object array used to set up the watching functions From 6962fd01d66b451c986c1a8b3eb43abfd2e9f18c Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 15:24:22 +0100 Subject: [PATCH 30/48] Syntax error --- apps/BLEcontroller/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 3f18ffa1c..01a2c78c8 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -313,7 +313,7 @@ const setMyWatch = (params) => { machine = machine.events({object: params.label, status: startEnd(params.bool)}); drawScreen(machine.screen); }, params.btn, {repeat:true, edge:"both"}); - drawWidgets(); + Bangle.drawWidgets(); }; /* object array used to set up the watching functions From fdbf4300ef20b9060ee4d1759d52c51936d73f7b Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 15:47:00 +0100 Subject: [PATCH 31/48] Change transmission frequency --- apps/BLEcontroller/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 01a2c78c8..8cb611273 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -19,6 +19,7 @@ bottom_btn = false; msgNum = 0; // message number +NRF.setConnectionInterval(100) /* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button From 39f62c1ab7c2c018e288c724ae69fbd5f0084dca Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 15:49:19 +0100 Subject: [PATCH 32/48] Try once at beginning of app --- apps/BLEcontroller/app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 8cb611273..7fd908d59 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -20,6 +20,8 @@ bottom_btn = false; msgNum = 0; // message number NRF.setConnectionInterval(100) +Bangle.loadWidgets() +Bangle.drawWidgets() /* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button @@ -314,7 +316,6 @@ const setMyWatch = (params) => { machine = machine.events({object: params.label, status: startEnd(params.bool)}); drawScreen(machine.screen); }, params.btn, {repeat:true, edge:"both"}); - Bangle.drawWidgets(); }; /* object array used to set up the watching functions From 5ca81d9bfbcc0c8351c3bc4ed2f25c186cb4fbdc Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 16:01:50 +0100 Subject: [PATCH 33/48] Tidy up --- apps/BLEcontroller/app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 7fd908d59..6f8b70e1b 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -19,9 +19,9 @@ bottom_btn = false; msgNum = 0; // message number -NRF.setConnectionInterval(100) -Bangle.loadWidgets() -Bangle.drawWidgets() +NRF.setConnectionInterval(100); +Bangle.loadWidgets(); +Bangle.drawWidgets(); /* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button From e8f8703b36cb4688e2b04cddd0480c73ace3bcff Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 16:06:10 +0100 Subject: [PATCH 34/48] Cosmetic change to give gap to widgets --- apps/BLEcontroller/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 6f8b70e1b..ba172b047 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -344,7 +344,7 @@ const drawButton = (params,side) => { text = params.secondary_text; icon = drawIcon(params.secondary_icon); } - g.fillRect(0+x,24,119+x, 239); + g.fillRect(0+x,28,119+x, 239); g.setColor(0x000); g.setFont("Vector",15); g.setFontAlign(0,0.0); From 7b6fe2f0d2eaa6a3a49d55a8f32ed30c78e1646e Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 17:30:19 +0100 Subject: [PATCH 35/48] Major refactoring to three apps --- apps.json | 2 +- apps/BLEcontroller/{app-big.js => app-ex2.js} | 342 +------------- apps/BLEcontroller/app-joy.js | 441 ++++++++++++++++++ 3 files changed, 466 insertions(+), 319 deletions(-) rename apps/BLEcontroller/{app-big.js => app-ex2.js} (62%) create mode 100644 apps/BLEcontroller/app-joy.js diff --git a/apps.json b/apps.json index 79923cab2..ac0decf97 100644 --- a/apps.json +++ b/apps.json @@ -1779,7 +1779,7 @@ "description": "A configurable controller for BLE devices and robots, with a basic four direction joystick. Designed to be easy to customise so you can add your own menus.", "tags": "tool,bluetooth", "readme": "README.md", - "allow_emulator":true, + "allow_emulator":false, "storage": [ { "name": "BLEcontroller.app.js", "url": "app.js" }, { "name": "BLEcontroller.img", "url": "app-icon.js", "evaluate": true } diff --git a/apps/BLEcontroller/app-big.js b/apps/BLEcontroller/app-ex2.js similarity index 62% rename from apps/BLEcontroller/app-big.js rename to apps/BLEcontroller/app-ex2.js index 2ad91ba54..a24d7805b 100644 --- a/apps/BLEcontroller/app-big.js +++ b/apps/BLEcontroller/app-ex2.js @@ -25,15 +25,12 @@ declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_auto = {value: false}; -var status_mic = {value: true}; var status_spk = {value: true}; var status_face = {value: true}; -var status_chess = {value: false}; var status_iris_light = {value: false}; var status_iris = {value: false}; -var status_wake = {value: false}; var status_hover = {value: false}; +var status_dome = {value: false}; /* trsnsmit message where @@ -72,34 +69,6 @@ Add an additional element to the icons array with a unique name and the data from the Image Object */ const icons = [ - { - name: "walk", - data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" - }, - { - name: "sit", - data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" - }, - { - name: "joystick", - data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" - }, - { - name: "left", - data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" - }, - { - name: "right", - data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" - }, - { - name: "forward", - data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" - }, - { - name: "backward", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" - }, { name: "back", data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" @@ -111,30 +80,6 @@ const icons = [ { name: "spk_off", data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" - }, - { - name: "mic_on", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" - }, - { - name: "mic_off", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Wf47/HJZLjHZ45RHrI7NHJYhLHqoZJA54hNHr5lTXL6vPSra5jKbo9REZrLRHa5DTXp47jAA7TTF7INLRqY7fdKavhXKo5te6wA==" - }, - { - name: "comms", - data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" - }, - { - name: "dalek", - data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" - }, - { - name: "k9", - data: "gEBAP4B/AP4B/AP4B/AP4B/AKAADIf5N/IaIAJJv5LZLeIARffZNdD5JN/KLYATC65RbAGrHlJ/5P/JuYrRJfovNJf4BdAFJL/Jv5N/Jv5L1Jv5PvJv5L7Jv5PpAGpN/dv5HzAP4B/AP4B/AP4B/AP4B/ALg" - }, - { - name: "pawn", - data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" }, { name: "facerecog", @@ -148,14 +93,6 @@ const icons = [ name: "awake", data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" }, - { - name: "wag_h", - data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" - }, - { - name: "wag_v", - data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" - }, { name: "happy", data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" @@ -175,6 +112,10 @@ const icons = [ { name: "speak", data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" + }, + { + name: "dalek", + data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" } ]; @@ -203,47 +144,6 @@ The global variable should be declared at the start of the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var joystickBtn = { - primary_colour: 0x653E, - primary_icon: 'joystick', - primary_text: 'Joystick', - }; - -var turnLeftBtn = { - primary_colour: 0x653E, - primary_text: 'Left', - primary_icon: 'left', - }; - -var turnRightBtn = { - primary_colour: 0x33F9, - primary_text: 'Right', - primary_icon: 'right', - }; - -var k9Btn = { - primary_colour: 0x653E, - primary_text: 'K9', - primary_icon: 'k9', - }; - -var dalekBtn = { - primary_colour: 0x33F9, - primary_text: 'Dalek', - primary_icon: 'dalek', - }; - -var tailHBtn = { - primary_colour: 0x653E, - primary_text: 'Wag Tail', - primary_icon: 'wag_h', - }; - -var tailVBtn = { - primary_colour: 0x33F9, - primary_text: 'Wag Tail', - primary_icon: 'wag_v', - }; var happyBtn = { primary_colour: 0x653E, @@ -274,17 +174,6 @@ var faceBtn = { value: status_face }; -var chessBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'pawn', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'pawn', - value: status_chess - }; - var irisLightBtn = { primary_colour: 0xE9C7, primary_text: 'Off', @@ -307,17 +196,6 @@ var irisBtn = { value: status_iris }; -var wakeBtn = { - primary_colour: 0xE9C7, - primary_text: 'Sleeping', - primary_icon: 'sleep', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Awake', - secondary_icon : 'awake', - value: status_wake - }; - var hoverBtn = { primary_colour: 0xE9C7, primary_text: 'Off', @@ -329,38 +207,16 @@ var hoverBtn = { value: status_hover }; -var autoBtn = { - primary_colour: 0xE9C7, - primary_text: 'Stop', - primary_icon: 'sit', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Move', - secondary_icon : 'walk', - value: status_auto - }; - -var micBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'mic_off', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'mic_on', - value: status_mic - }; - -var spkBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'spk_off', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'spk_on', - value: status_spk - }; + var domeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'dalek', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'dalek', + value: status_dome + }; /* CONFIGURATION AREA - SCREEN DEFINITIONS @@ -372,40 +228,8 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ + const menuScreen = { - left: k9Btn, - right: dalekBtn, -}; - -const k9MenuScreen = { - left: wakeBtn, - right: joystickBtn, - btn1: "pawn", - btn2: "wag_h", - btn3: "back" -}; - -const joystickScreen = { - left: turnLeftBtn, - right: turnRightBtn, - btn1: "forward", - btn2: "backward", - btn3: "back" -}; - -const tailScreen = { - left: tailHBtn, - right: tailVBtn, - btn3: "back" -}; - -const commsScreen = { - left: micBtn, - right: spkBtn, - btn3: "back" -}; - -const dalekMenuScreen = { left: faceBtn, right: speakBtn, btn1: "hover", @@ -427,13 +251,7 @@ const irisScreen = { const lightsScreen = { left: hoverBtn, - right: spkBtn, - btn3: "back" -}; - -const chessScreen = { - left: chessBtn, - right: autoBtn, + right: domeBtn, btn3: "back" }; @@ -476,51 +294,11 @@ inversed and the new value transmitted. */ /* The Home State/Page is where the application beings */ + const Home = new State({ - state: "Home", + state: "DalekMenu", screen: menuScreen, events: (event) => { - if ((event.object == "right") && (event.status == "end")) { - return DalekMenu; - } - if ((event.object == "left") && (event.status == "end")) { - //status_auto.value = !status_auto.value; - //transmit(this.state, "auto", onOff(status_auto.value)); - //return this; - return K9Menu; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const K9Menu = new State({ - state: "K9Menu", - screen: k9MenuScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - return Joystick; - } - if ((event.object == "left") && (event.status == "end")) { - status_wake.value = !status_wake.value; - transmit(this.state, "auto", onOff(status_wake.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const DalekMenu = new State({ - state: "DalekMenu", - screen: dalekMenuScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } if ((event.object == "right") && (event.status == "end")) { return Speak; } @@ -539,41 +317,7 @@ const Speak = new State({ screen: speakScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { - return DalekMenu; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Chess = new State({ - state: "Chess", - screen: chessScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return K9Menu; - } - if ((event.object == "right") && (event.status == "end")) { - status_auto.value = !status_auto.value; - transmit(this.state, "follow", onOff(status_auto.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_chess.value = !status_chess.value; - transmit(this.state, "chess", onOff(status_chess.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Tail = new State({ - state: "Tail", - screen: tailScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return K9Menu; + return Home; } transmit(this.state, event.object, event.status); return this; @@ -585,7 +329,7 @@ const Iris = new State({ screen: irisScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { - return DalekMenu; + return Home; } if ((event.object == "right") && (event.status == "end")) { status_iris_light.value = !status_iris_light.value; @@ -607,11 +351,11 @@ const Lights = new State({ screen: lightsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { - return DalekMenu; + return Home; } if ((event.object == "right") && (event.status == "end")) { - status_spk.value = !status_spk.value; - transmit(this.state, "iris_light", onOff(status_spk.value)); + status_dome.value = !status_dome.value; + transmit(this.state, "dome", onOff(status_dome.value)); return this; } if ((event.object == "left") && (event.status == "end")) { @@ -624,44 +368,6 @@ const Lights = new State({ } }); - -/* Joystick page state */ -const Joystick = new State({ - state: "Joystick", - screen: joystickScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - transmit("Joystick", "joystick", "off"); - return Home; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -/* Comms page state */ -const Comms = new State({ - state: "Comms", - screen: commsScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "left") && (event.status == "end")) { - status_mic.value = !status_mic.value; - transmit(this.state, "mic", onOff(status_mic.value)); - return this; - } - if ((event.object == "right") && (event.status == "end")) { - status_spk.value = !status_spk.value; - transmit(this.state, "spk", onOff(status_spk.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - /* translate button status into english */ const startEnd = status => status ? "start" : "end"; diff --git a/apps/BLEcontroller/app-joy.js b/apps/BLEcontroller/app-joy.js new file mode 100644 index 000000000..66bad3934 --- /dev/null +++ b/apps/BLEcontroller/app-joy.js @@ -0,0 +1,441 @@ +/* +========================================================== +Simple event based robot controller that enables robot +to switch into automatic or manual control modes. Behaviours +are controlled via a simple finite state machine. +In automatic mode the +robot will look after itself. In manual mode, the watch +will provide simple forward, back, left and right commands. +The messages will be transmitted to a partner BLE Espruino +using BLE +Written by Richard Hopkins, May 2020 +========================================================== +declare global variables for watch button statuses */ +top_btn = false; +middle_btn = false; +left_btn= false; // the left side of the touch screen +right_btn = false; // the right side of the touch screen +bottom_btn = false; + +msgNum = 0; // message number + +NRF.setConnectionInterval(100); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +/* +CONFIGURATION AREA - STATE VARIABLES +declare global variables for the toggle button +statuses; if you add an additional toggle button +you should declare it and initiase it here */ + +var status_auto = {value: false}; +var status_chess = {value: false}; +var status_wake = {value: false}; + +/* trsnsmit message +where +s = first character of state, +o = first three character of object name +v = value of state.object +*/ + +const transmit = (state,object,status) => { + msgNum ++; + msg = { + n: msgNum.toString().slice(-4), + s: state.substr(0,4), + o: object.substr(0,4), + v: status.substr(0.4), + }; + message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; + NRF.setAdvertising({},{ + showName: false, + manufacturer: 0x0590, + manufacturerData: JSON.stringify(message)}); +}; + +/* +CONFIGURATION AREA - ICON DEFINITIONS +Retrieve 30px PNG icons from: +https://icons8.com/icon/set/speak/ios-glyphs +Create icons using: +https://www.espruino.com/Image+Converter +Use compression: true +Transparency: true +Diffusion: flat +Colours: 16bit RGB +Ouput as: Image Object +Add an additional element to the icons array +with a unique name and the data from the Image Object +*/ +const icons = [ + { + name: "walk", + data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" + }, + { + name: "sit", + data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" + }, + { + name: "joystick", + data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" + }, + { + name: "left", + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + }, + { + name: "right", + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + }, + { + name: "forward", + data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" + }, + { + name: "backward", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" + }, + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "mic_on", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" + }, + { + name: "comms", + data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + }, + { + name: "pawn", + data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "wag_h", + data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" + }, + { + name: "wag_v", + data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" + } + ]; + +/* finds icon data by name in the icon array and returns an image object*/ +const drawIcon = (name) => { + for (var icon of icons) { + if (icon.name == name) { + image = { + width : 30, height : 30, bpp : 16, + transparent : 1, + buffer: require("heatshrink").decompress(atob(icon.data)) + }; + return image;} + } +}; + +/* +CONFIGURATION AREA - BUTTON DEFINITIONS +for a simple button, just define a primary colour +and an icon name from the icon array and +the text to display beneath the button +for toggle buttons, additionally provide secondary +colours, icon name and text. Also provide a reference +to a global variable for the value of the button. +The global variable should be declared at the start of +the program and it may be adviable to use the 'status_name' +format to ensure it is clear. +*/ + +var joystickBtn = { + primary_colour: 0x653E, + primary_icon: 'joystick', + primary_text: 'Joystick', + }; + +var turnLeftBtn = { + primary_colour: 0x653E, + primary_text: 'Left', + primary_icon: 'left', + }; + +var turnRightBtn = { + primary_colour: 0x33F9, + primary_text: 'Right', + primary_icon: 'right', + }; + +var tailHBtn = { + primary_colour: 0x653E, + primary_text: 'Wag Tail', + primary_icon: 'wag_h', + }; + +var tailVBtn = { + primary_colour: 0x33F9, + primary_text: 'Wag Tail', + primary_icon: 'wag_v', + }; + +var chessBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'pawn', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'pawn', + value: status_chess + }; + +var wakeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Sleeping', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Awake', + secondary_icon : 'awake', + value: status_wake + }; + +var autoBtn = { + primary_colour: 0xE9C7, + primary_text: 'Stop', + primary_icon: 'sit', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Move', + secondary_icon : 'walk', + value: status_auto + }; + +/* +CONFIGURATION AREA - SCREEN DEFINITIONS +a screen can have a button (as defined above) +on the left and/or the right of the screen. +in adddition a screen can optionally have +an icon for each of the three buttons on +the left hand side of the screen. These +are defined as btn1, bt2 and bt3. The +values are names from the icon array. +*/ +const menuScreen = { + left: wakeBtn, + right: joystickBtn, + btn1: "pawn", + btn2: "wag_h", + btn3: "back" +}; + +const joystickScreen = { + left: turnLeftBtn, + right: turnRightBtn, + btn1: "forward", + btn2: "backward", + btn3: "back" +}; + +const tailScreen = { + left: tailHBtn, + right: tailVBtn, + btn3: "back" +}; + +const chessScreen = { + left: chessBtn, + right: autoBtn, + btn3: "back" +}; + + +/* base state definition +Each of the screens correspond to a state; +this class provides a constuctor for each +of the states +*/ +class State { + constructor(params) { + this.state = params.state; + this.events = params.events; + this.screen = params.screen; + } +} + +/* +CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS +This area defines how each screen behaves. +Each screen corresponds to a different State of the +state machine. This makes it much easier to isolate +behaviours between screens. +The state value is transmitted whenever a button is pressed +to provide context (so the receiving device, knows which +button was pressed on which screen). +The screens are defined above. +The events section identifies if a particular button has been +pressed and released on the screen and an action can then be taken. +The events function receives a notification from a mySetWatch which +provides an event object that identifies which button and whether +it has been pressed down or released. Actions can then be taken. +The events function will always return a State object. +If the events function returns different State from the current +one, then the state machine will change to that new State and redrsw +the screen appropriately. +To add in additional capabilities for button presses, simply add +an additional 'if' statement. +For toggle buttons, the value of the appropiate status object is +inversed and the new value transmitted. +*/ + +/* The Home State/Page is where the application beings */ + +const Home = new State({ + state: "K9Menu", + screen: menuScreen, + events: (event) => { + if ((event.object == "right") && (event.status == "end")) { + return Joystick; + } + if ((event.object == "left") && (event.status == "end")) { + status_wake.value = !status_wake.value; + transmit(this.state, "wake", onOff(status_wake.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Chess = new State({ + state: "Chess", + screen: chessScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_auto.value = !status_auto.value; + transmit(this.state, "follow", onOff(status_auto.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_chess.value = !status_chess.value; + transmit(this.state, "chess", onOff(status_chess.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Tail = new State({ + state: "Tail", + screen: tailScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* Joystick page state */ +const Joystick = new State({ + state: "Joystick", + screen: joystickScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + transmit("Joystick", "joystick", "off"); + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* translate button status into english */ +const startEnd = status => status ? "start" : "end"; + +/* translate status into english */ +const onOff= status => status ? "on" : "off"; + + +/* create watching functions that will change the global +button status when pressed or released +This is actuslly the hesrt of the program. When a button +is not being pressed, nothing is happening (no loops). +This makes the progrsm more battery efficient. +When a setWatch event is raised, the custom callbacks defined +here will be called. These then fired as events to the current +state/screen of the state mschine. +Some events, will result in the stste of the state machine +chsnging, which is why the screen is redrswn after each +button press. +*/ +const setMyWatch = (params) => { + setWatch(() => { + params.bool=!params.bool; + machine = machine.events({object: params.label, status: startEnd(params.bool)}); + drawScreen(machine.screen); + }, params.btn, {repeat:true, edge:"both"}); +}; + +/* object array used to set up the watching functions +*/ +const buttons = [ + {bool : bottom_btn, label : "bottom",btn : BTN3}, + {bool : middle_btn, label : "middle",btn : BTN2}, + {bool : top_btn, label : "top",btn : BTN1}, + {bool : left_btn, label : "left",btn : BTN4}, + {bool : right_btn, label : "right",btn : BTN5} + ]; + +/* set up watchers for buttons */ +for (var button of buttons) + {setMyWatch(button);} + +/* Draw various kinds of buttons */ +const drawButton = (params,side) => { + g.setFontAlign(0,1); + icon = drawIcon(params.primary_icon); + text = params.primary_text; + g.setColor(params.primary_colour); + const x = (side == "left") ? 0 : 120; + if ((params.toggle) && (params.value.value)) { + g.setColor(params.secondary_colour); + text = params.secondary_text; + icon = drawIcon(params.secondary_icon); + } + g.fillRect(0+x,28,119+x, 239); + g.setColor(0x000); + g.setFont("Vector",15); + g.setFontAlign(0,0.0); + g.drawString(text,60+x,160); + options = {rotate: 0, scale:2}; + g.drawImage(icon,x+60,120,options); +}; + +/* Draw the pages corresponding to the states */ +const drawScreen = (params) => { + drawButton(params.left,'left'); + drawButton(params.right,'right'); + g.setColor(0x000); + if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} + if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} + if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} +}; + +machine = Home; // instantiate the state machine at Home +Bangle.drawWidgets(); // draw active widgets +drawScreen(machine.screen); // draw the screen From 1e98a6d73b42e1aad89f0378f9105ef46516c010 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 17:42:46 +0100 Subject: [PATCH 36/48] Update to READ.ME --- apps/BLEcontroller/README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 0929a9fd7..3f9dfa6b8 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -4,6 +4,8 @@ A highly customisable state machine driven user interface that will communicate Amaze your friends by controlling your robot, your house or any other BLE device from your watch! + + To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: * message number (3 characters) * screen name (3 characters) @@ -12,7 +14,8 @@ To keep the messages small, commands are sent from the Controller to the BLE tar The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. -Gordon Williams' EspruinoHub is an excellent way to transform BLE advertisements into MQTT messages for further processing. +Gordon Williams' EspruinoHub is an excellent way to transform thse BLE advertisements into MQTT messages for further processing. They can be subscribed to via the following MQTT topic (change the watchaddress, to the MAC address of your Bangle.js) +/ble/advertise/wa:tc:ha:dd:re:ss/espruino/# ## Usage @@ -25,9 +28,11 @@ Most changes are possible via data, rather than code change. The default package contains three configurations: * a simple home light and sockets controller UI (app.js) * a robot controller UI with joystick (app-joy.js) -* a simple static assistant controller (app-ass.js) +* a simple static assistant controller (app-ex2.js) -You can try out the other configurations by deleting app.js and renaming the file you want to app.js. +You can try out the other configurations by deleting app.js and renaming the file you want to try as app.js. + +I have tested out the application to as many as eight screens without problems, but four screens are usually enough for most situations. ## Controls @@ -37,7 +42,7 @@ I have used the convention of red/green for buttons that are switches and blue b ## Requests -In the first instance, please consult my blog post on this application here. +In the first instance, please consult my blog post on this application [here](https://k9-build.blogspot.com/2020/05/controlling-k9-using-bluetooth-ble-from.html) ## Creator From 262b12277761cfe0e7cae56bf8ac8ee45644d218 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 17:55:11 +0100 Subject: [PATCH 37/48] Change video format --- apps/BLEcontroller/README.md | 2 +- apps/BLEcontroller/video.png | Bin 0 -> 178721 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 apps/BLEcontroller/video.png diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 3f9dfa6b8..ad2d5aad2 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -4,7 +4,7 @@ A highly customisable state machine driven user interface that will communicate Amaze your friends by controlling your robot, your house or any other BLE device from your watch! - +[![Video of watch and robot](./video.png)](https://www.youtube.com/embed/acQxcoFe0W0 "Control your robot from your Watch") To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: * message number (3 characters) diff --git a/apps/BLEcontroller/video.png b/apps/BLEcontroller/video.png new file mode 100644 index 0000000000000000000000000000000000000000..bd25e26a240e53ad6b09e0ba5eb1ab950f966d2b GIT binary patch literal 178721 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�{z8ifd!0&%p2*ue!mPL|*kpYfz(4-8KeME7^EdwT zU*Ftm%bE{=@r&I0c5mflXKio2NPPJ`-d(Hj2V7`r@ zIyxv-mN2c1u4%){exC^&;iYrUcj&80TMG45iqdWeLL`Kx_JXW>s=wEs5s};^fU0;D z&}6#>J0Yp4@!}cp=3VSK{=96g5eD&?-I1qVOUsSMtM?p2a*`-!-;rAa={8`buW7I`UoKN z69&C!Pbp7;=oSHCE-ZYRN4Q_I$YI_DrOksLffkK;3C0Nwkx-Nc)*mYx%EAxYPL^Tb zTR&BIil?~|wpkAjToZPxVOBZ1QfT09lBCbon<5sn1P|kAJfdpj>6}b}IE`3C!fEbB zxlx33oVtaQg#qyfxDWDHbaFBZ!50|jofw{L&cq#XH3lF%pxvJ=wtmtdLTbI@y*}%i z)cMEp?3Z6&@97t_fcTBqUmK76dJ&4-x7!tD>ZM%QSVKo)t*6leK0vc%QuudnO8q(A z{ZwH!t~Q4Whi2{sU(by74lWP>noGO-0*A-VMLp`g5(n^EXSaDA@3+69Y_&0}D@S=K z&v5eW@;;+opY4<%a$>@`Eo1LQ%IrlvAfbwh<;9y`Sn28dVBFYcn^MJpWDVnOB|~5s z7{eQShnLs%zx&Dr>AbI!)mhsM2f>X;woi>RnI62X=GT1a+2J?K2!cEK$Z!8# z!`p-BS07z1&+oy$Yu~%}k%3GxDqZjz;(Yq5W?#K_SI@c;AF>8l1G5!M76xJXlb`%# z^WXk=|9xSuES)n~@cWI!wu6nG{?D9AgFqHxDA5lkrw{|MlPdo12^0 zKixdM{l(_>w=Qkox)c$MhdwKm^YrmzXyF=hblb*Xef`Sj!j*P|PGOxYB=W56yyFKk zXYkUpCXDy99Dnq~AIwRt|LK45ALsGBSC-COO>%e6PuXPV9SDa9S=zt<&;HrwpZueL z+(OU8&0qa%e{J(0{U`tN=5OU4z0)(3j8Vk|0c%`XXjbYQs38_H43r^upX~(P55>Im zcIv-)KKFE3F{>IIiaqbyORsVh{wf48Ynp_U2+oMUyM_c2;%W;`35#1PdK-y4c+EzL zbAEix%e8Op&Oj0O)*=he?g=volft*)@>WMBTxo8M0Cu0nMH!uGeva}Kvp1p2YjRl| z^SFK97yuWX`@$QI&R_xCDCywMRvkutmXKKMf!2-!gqWs=ChPRh&JWCsCUxvQ{VIp#FM4*YlV2iqBN; zbbMBR!{$UMc6N%!ns;cx+pyIEfxH!I>jnp0$hH!uWH?a7{jg{f&4lh|z|fxcngL-r z+?{z1ySY0`y?VppgXrQc7klwh8p>0~$2}_rdCku-sCaZK;r`*VSsfo8wcwCP3Pl2i z4A4822Y4Xg4G>uI=AlT=Sfx_FXTk||aBAYS;jinji29I&z9qy#H zQ!w^{b6H%wER$97h58m)G`7AX7v)ZhYReZPC?Y^EXQl zy3#z%{fv#zK9g{=)^*u9_jJY#{tsoFqkxyn-^ZEApYU&zdy*$AcRJcEj5Pr9Ro@V1 zKK5MygZ%54dyxFi`xL76O&4BBq zlB{7PclM*-$vo_5;XjrW91b!v#JB`1Lnq3c(+Uv0=QZ9`_jZCF3E50fK{fDWX^EoJK*kMe-{@`S?;9 z6;&9Ss6V}2!&kJ_5N~e1{NuO1|K`8?&;Rb4obP^2FfLRW`{<+3H{bu4Kdi}Os_jxR zDZIf<0U`FdRaL;XqJVf0R<_Sce-XmE1{1}EpT&jyx#i#c?t7c>{?D9L8 zd1JOpxzys+D*$9bo4=h}dZ~$P*NbLC5-G?pe6rwuS;-~yU&zG zk_tk)C$)IRlHYyry@XeX@^um@i)LA;ib1@!N3w^qK&uPR0}*wWz#||CnQ);Uuc67% zrr}2MMd;IocKRtVNJd#+5ZonL3=;P}gF#rpCc}l_tj8f>SB6;{1ug2U`zuQ;HY3m) z1cVx8M7R)a>Rz5LcnqEtO`#;8cW{nHX>ipc0*Y`9lBr|CFg0!^L>uQagcP%osV>iu|Xy9&GM? z`emWwPdA_c{L{^sAGPKw&-ZNG6rIUywonu}I2f9T=N&JgFJbT9m>MNg+q*S5GmmGi1m6&{&jul! zfe}9~B^XS>vhWnE_@Yq>svW_2cTt{5o*!i=F5FE*y==UHUL{ zlIZ5gUL)7K&#-n7ov8&o=AY_0hciB_?-Z1-80&C~UUwWj9+N@xTHeCn`8)q+ z=Ww(hp>v5&rtpNIcx*hL6gxlZwxBu##2#P{e}#Oh1CJ zYEfti>7&a)Kv+b-+77&D$`HDHhnE8esjw7K@UgUO-@a3J0WsNWT?^r=PH?l*#sf+b z%dldBV|;C)vrI7p;W3XWWoJ%-vg^_MPC+$z#yV%QE*rYR!OMd-ASn_E z$4hX!6WZD}0MUbWOCiIW-z}y*u8+c|YoKObv#hHFZIqdlJAL6AzBViMJ0VaADT%|Ioq62G@BTLX4*Y}n8a&Za;yx1)>Yw{HFoI@r)4)EB z^#`7Wg-OW=YKSqeg9O}_8p>^Wc_?tG>6y~Ybtud;sIUh}!HA_;z*eorA^R^7X@Uwc=Fw!DW>(JcKI$?$Kde7^RKDuv}| z)8cJ|Q=rdX{!XOF9AE&cd-^iJu0I2#Ki|0aM@UsSrl^%+I&(ZMJ`mb|gf}yJ{ta%; zh1Ui+t5=N)kSWu91UqQ*mKA#U&i&1g?)_Pw$FDZ;mo@X--+m|J6~1X9=830i;mVxq zx$|x9UMtlhykJt4peG#4L@DEk{I!?aYgeyruD$cEhF{NId~NfmKmO^Yvwm3!%4GfZ zyrD+dFf{8gXsWMQ5b75OF@JHbHAXCpnaFQYF5a#ml_3DficV-z!59D@gxy$90W$Z5 zaKJc`osbO+>IA!WB9EWk9>zXMp@3xueRYl8Q5ti4u8%vWHP8q!*<%Ow`)LUeGL5Xi zNFN3JI&e&w>AsUp8#n|9Mx_vjp|qp|?ZC3%?~@o1vdlT4H({v*;>i{|ANRGXoC&YhsRUr5qsmLYwO;4! znNBaoQ{io|j6(GhaOuMOjcKbpVI+(->qU|~`}g9vC#^lX*&N*Mhnp97TJU`5!R9E% zaJqKSr!Zb5KaNU#2zhDt#~s-)i7S=ec>?gy6L%Tt1}dRF zRxt+fzXtK4P@Axvz1G~D?TP}BaF`HB_uMB?!78yq{j=*q<@66fh1gLz)4Sn`@KhbA z6Q(C4($k*DFa0z;1Qxu+i!)z$+{8M-EJK)k@jtOUh#~2`!i}qHrVMZCcKaZjcY!A% zt~c5V-=bL=t)G-MG-3%(JzssizOklxof)d41j1lPFXFxEGfmd)Kne#vMHI&}-30yW z!+hQTfzmLr1acsHMp1LX^B%zV1~gr8rQKOBm$iGVF^V7XJ1>k-COh`Yq>Qjr@zm** zkR>aVn1Tk?yc6CGFymn6Cd2<=rgqj+g$%poQUqumGgj5V`m%#<-reta{~%RA`ag7A z^HcL=ce<3T7}`UnarDh=Nc4@H?oFL@f3>3?ZNbg1nvqR@c;#A<)yL@_9_&XI4u-vv z3rXF6kVUxoYw_KxMgyLAuaEun-=BR0Vvsfx5=0>ilIs`sFbqFDNuVc;=3d2`{5+9n zOeUp?8+0+3$E!cCS>X%=%Ib;l)YDp+G5YAoAiz&1gv#~k>E)&K^s0O`O zxWYnvHtn*4AjBQ7Pr<4NPjk{oCD)XV{Wyz5;9B97cQDm4~sKK zV{Mu=$G`@q`nnd17VO^;2F$M6XF(1 z4j%j6oFL%=mo*rlgy(I@&@sl(pGhe$99uiH;7_9!b=cX9j2i=rvb9H^9hA>i_xU{D z{qE-&ZB9v<&O1JS&>9<=UiaJ2?QW^g?N7Gpn2R&pO)%Nk55mo}6b(&rw4cIxuXS6E zcZ!V%HVS^E3W5gi;Cem|#(63}5Djo=NrBG>+|%-I1Ffq`?7W|cZOTfp&d%wQ%T2oVPWam>6^ufdOBv!N z#vp2qC>)ygrTh9!0i~GoLh->;R^c&0Yu=4FWRz(aO=rCK%y_|#X>`|*Q4YZ(;=u@& zWCNeV)@)Db+dQuw*Lcdo0tZgW6&jcPb1?(w-S^%O7mT8IQ|CL&#WVl_KmbWZK~%}s z$51^mn=g7^h*cO=J0cd(p0@Q+Z5=%b_GA(A;mJw;ozGz|I_ejO?r&FouTuXj%V5_x zXJ(oIk~B1p_Pajt5NAw{QBk5!M#5f4ddzP4)kgjr!;`g{;rVV+GWYj@0D3&u4ifw-|0h=W7{il-Bn-x^$+dpLhx-B z)f5HrlpMH6nSsx%AMo}rJgw@5s_ykn4|p`h^h5kl?k|Kd+WP6`H4V>01Ir=-18SAk zj!V>qK~6@DQM9eV?_SF}nBGpmQ$pNul^D7G02vW?!gSrI44e^SZ47IA%*RS|%^+5@ zv2#{Lf+MS47~`C?MGD8*WYdJ;z0#I{aQDxe*Xj4ODWT^L)GVYYPgXeTC<2~Nk);-T zK?bJlaL~dnw@U)JeKQyOjk4z2&+fNBxY~Tudt+IjJn=6!|LZ^ahl8_A9iDeJtHyqH zPf~sc!@XV;R}RjJbLv~K-6S7Ih7|ppeuU&?V5zRBvxW{FV3)-tJIUdD zufO?P9$yPUYsW%WZ8&bgprjm@k_%V;X3!hxLMYOeXN>}MZU@>h*$@%#S&8CRB_{+K z8VNhC6xt?Lw{tx*-KrpgKqQB>+95#3%0{E<)nZ1hqZ|doaz1`qifNYaaf;x1is)1a zz1d|t?09gVM&0B3{~$c^dbW z>s%Q8{J1R6r>$vvvvZg(UCJUJ?Nstjyp67V^@Y+f;8@v=4PNzLb5t&6mI4^9R{hZ= z&kQ||pDslvfnY+V;RkFo+71iPN%PeUi$Wi@L%M_T2(>W)gM*j6LTmM*e!!{0FOh;5 zjTaa&JRKr$vgMj!cc`9Y+9@Rh`}y-if(h4DVc+ej?XbVg319oo#dCRxbz{6*5fEnt ztrYR4r1bBgehE|B8UD4>wGR(3SLO{EsGm>TspFGEcFwD!%y_-g1FovK2;dloFWO1| zDE_{iK|2XKh*5t=yM$k~wha~>`$Bl5oiRPaH*6Whl%2)wmrF}OTWFtxShViBE*`0| ziw3s-GA68xgzJ%q{ch=nsR#<45^_rF@C-x{vMFIn2o{~%{XS@>ocbw6W8K`Awv9Up zQ|8Q_Q#9}@QyRbP#b3HYv$fxQZg)#V8iVEE39nl|N$TccP zTO)tM*+j3Zf^6^)&PHigC6oeUbU=Lc7q05pr^)Q>*`TU8d5j!Z|p{M>4Kh z&sqPaO}~h_g-8D2557N(+WyVI_188R%bwzcIp8ji*&GsD5#YE1V^1-J|M25aHy;;j zOTzSDMpAL}?(;-mFBSBBn|e;hPzSL|!+aygp9OmjRLbK{@#rC9Si%dC8^+;bm8jw!1gSMSzR|+TI^xpj(6+ zVGVy6%WI&jVFo~W0TT;*<=n?S)uA2xw1I5~+`t@s^3wn=cwASYNsRE1kN& z_HX9?qSG)xMF;K%5lcw={h2IoTdxq}76^|3kG5c>426iq@6kfvMu-G)pbSj9u|CJl z{X11TeIdxwyoF&q2Pu#8v^MoI59jXnb~b3fWiMlAKV|f+V<1kJIeCy*b-HH`JE`(C zuUSgJ5N_>fYveU`FPuCoX8WwnxeHSHO&Xqxv-*8`6w!AEkN!tbJYKtufYT=md-2}F z7ka?O&iFD|=QP`tv}6(CB8Sr*R_<&@)}_|P2ze6R6h9@hcx~aLszzBnZ=TD5gvaHf zn)9HfZ2^-~jjxDNTseZM-yD+o{8<)!Z5mUbTRG~JFfBk|B@EPm8821!akJ_fj?Txut|H!wI8@qS+<{717ImotX10(q+LN$f@ z4q*StO2uBiv@w?obxc(i8V{?_ZY`KrF>uV>Qsv32uU~3k_xu)jt`3iYbUz4GAnYPt z_o%svMs@-xhCqOMR>iT#*AP^wExtZckbVilJc8;u+q{Um81n`{`qLk!OipgT_3d{z z2k*W$874;!o;hL|pb^udWfveZ#q;Tn8=FsVe6e}^x4&Daob>339TOh3i^9bghhAtc zk+n3B8az)rweg_2iwh}-hs_b#eR_pkpvFK#RKyNp)ei?df-TL@a_AWh7#vG3BT)Af zpyrTl0!k2Eidn5^niF3mfB~yM9t>CCSwjbTg4fI9^BW}%zppAGO2swvU&Ca+?-*@> z3%-QKz?ztf;V1jBLACg1^+_EF`7)Cxzp?UI_GLibq!i~hX`T?&XLPXW#M>3dj4x7x<;xD@>-G?Yd-C&8h%PbVDC z9cTG9&*IpJhb5WZxpBMAT3i3py)y~NgFK7VcH`)z&NFA@A!}?3#XT>?TOhPhAL~1- zK7qQIpm~&%cpASn(^v?GKuGA2!fMzU$mgpZX7#aHfM6CM3RS$f%>_l+peAUeR*V~sOl1fa>7Q9 z9ZDqBRaEw|?ka+hN^%813^Cd0{gb zoJZN9j~AALrGyBFkt)fF2s$s}WC|9K_n&m0GBX~6Nn`qfE+R(c?!a5$-8WVzI-*>q z!Nub>?&r7e&;RQ3+|I~c^0=Set1j;^KP#(c_u)2NOQ_Po0x_7~*B%(XD(ih$Z$GW8 z2Ud|)&QmjvcKz)E?QUzH&-mW!)oc2;t!u}(%%NeX6+!?2VZ14(dv){g{JVcMYd)cq z=YbJJ$sl-Kt?mtyAj@wQRLEq_2}^N@A;mE`V`mp!X% z8?;YxMT6{l7SN+6sxjsM)r*_UrScwLIoGpjZ@V8yGE+uRH}AjydKqrNH-g{p+t=Dj z`!E;q>g98z=3J_boC|nctyf48ES|cV3X}7`Sob z;_GjwKod^0>c2LuK{=O_#C$SstXwyLVE*X@1s+~_iiDaBwWRlGF-5DrO)$bIr2 z6%whKFiX9SJXtL))yK_8z~@p94FF6KUkzjT;cBVwjtpmE+AHpMi5rB*3<^x~3P;rZ zT;9VHaJGtT0$0(Ha5V zLhad|j-if*k5W1g!K;eSOgh_%w5=aIjCUIJQemAMYw>9tlDB9lL+ECEvwhKS90{+d z9fr8y06m+~ezQcE+wsbsc;f5`*MwREW4wf5aWMj%;`$`~KWb3hB>-KmIWli$T<#RB zfeI!#g%xYDgsTYTIB;lZ?!W~6+pSG|G#m3i7(96p@8C6O2$?^0;R_0a=QyF-a5cQu zZ`0n6E^rN=p2c4enuj`JTd46|g!F`N@`ThIv1XxgedOuZMEBOb(#)r(oY#6Li4&CZ zifWi+B1ge$Y=CX?r#T~YUMqr;GdA!($%`oHhyEl*Iv6e^DpLUzGzR$yUiCv^T?AP4R!O~?kEL9$LoD~ve0@-PLrrK z{ixtKE`3MOd9OpxA%pKk$AndH68=pVUW~^iu9&Mae%7X@!JfRKfGx0fu9eVS?&6|j zIC&nPC~&)eLmq*?Anm)Yr^3HPD~e&SwyS>lPvp#aaDN0YImyV~;jH^3FNglh8ByyZ z;3xVKoMQyUGk67`j`tX!kXe)m#k@15S7ZmyE2~~*1|Lh|%=oN{b$=;!ma+flMMyWfxY3Ej0nZ4J&|*7nth%8QP4EkUMYqNTnT)4ja; zTmQyiE{qoPYhe*txwL&2`l*!AKvCtGbjOgBHC08oZ`~Y3y!}=ala;Xxz>|<~k1ku; zWDm6HD+VakLJfh#W`@rbRBlLHCL6m4c38z+m}SC? z-Sb|7gm|7%UV;ok-9BGRu#F)fn4E5)u^g?gH=;4O7weOf<4)TGhNY_=I5sb_)(d%L z5mY;HKYzhenG=q~4%b#@N9VDkcI>gNXjt=9zvrO<*JiI56XKX5ou2Ybm^F8?=8g0x zCho^I50C)S&a@5otpBIg*7q3@8m%l?Jc9|mX~-O)GLum9_` zJkilFKG__9)C&FkS-7=vK4D??{iDLZCkr3FNV)ADRJVV@H{M!rnG{x$b5#B6;DOLsTVdF9mQ@rGvC>`9EN-r=7`PeOo1bq_zd3`XN) z!l&VOV1eTrmekVUDaVMLbtUl&n1`n$CSgs;oNhkPGrrFb5QJlOdtUh$tnJ3qL3l{+ z4i7RP(2rm{Ds)YmF;4I`_#Ag&v9P(1gA4&l28 z$cr)17^2qa!Ry65qLtutwz-!STOP{O3^>afgwm()(*=fJ<4w4-zIr)M;c@d<+LF*R z^aI!S)!Tdyl6fBr!)f1*Sy2K8-KlUSIRJl-V(?(sBwJL@o|b1%lz@~HqL2@gF)}sH zcOcW)$;egR=xS@Gm~TRIGY+~(2|Z&BDIWlM(3prqiw?;H&y!IUkTi9CF$$*lejd1$ z897vaJVZQWjP1&e*HiiNV2t6$AUQoD{NWRQR4<9qtNJE$t#5stYdq)e_kp3i6<L;c$+#_1H{w7a%2`3knY$Sp`)WCJ|tXTj*@b}sO1 zKaHSQ>4XzB5+R460GfdsGer;(u=qZ05>j2?{ouPHXm7lQbVp@#Z?4c|iHOGA7*mWUA$6{Gl6af)CbuaI(!3tK}5h1#i zTZsshCe179nGqIHQGcE`CuQKS0luFSsxHEhfT%w7u<7Pt#@$<~@(4^rH-_GM%Dgp-?(K1@*#9;+|>OY?r({K~UJ9h2Ra zD-hKZItlU;2+TX!H%*%I2yuhIHVoX^Pp-c6yw2too=w4@jvn@XlaAeNQ7hx?MDsh( z^H`2j9`|oGXLo01x@}TQ4g))k9%oyeeAt5JGo5X;|6AYMoP6u`&8A%x_G;g;-^0u) zA!~#-pMAO6{Osd4jZ7$INIZL*QVQMx%$v@uNg+LGf4BR2$a`;>NYZ@I^9H6=bMuBy z^~7rjj3Cx|Jo!AuGK*PXvF=&N1oUj%U)h|GW%$I?2mK~h`(|?p2c=QJW^r`}$>VT) zr=8)2o6rg#;r2y1+YM5o9p16YTJ#d~T_LXrB@yIl_xtcjbVmP4gO3>)F_ug)I(Rg~ zg~Fy)KKw8dh^SXXGf)G!w$0rLi}RlGUVZO(v}OoVFf-v^Jrvo)()A@-P=s~`kp+6@ zY~{1K@Z%hASielD8^46(ql}6nQ0>`rs$WKUPbzdQ`@CfY_e!Pz@WT(s5OSa%*@2JX z>{+3&ql~i~U*6t4$jCT~2g`K~zGXbX)4|2~D_%8jZnj_I?Hl)Ngd#6&X>9Zlt7+Q{ zu#!G3a5tjs{=iQ}3H#qqnKgno7veu2k)#~BSW6rjQdO1$k;Q59oC11LXwi}kC){>- zcxW;&!>3WR=7cg7Qd$g_nb)o@JXs|vJf6!^E=Z(;@t6Y2oS?BxF1gmckOz@#33dj& zJC-k?k7wrvR?qd)za{Wfcfq;~ZMEAlNg-5bnSz#;NCvakN zYZzn)os9WrtBhHXRQo9ap#dB3MY|eXlc=)bOduLyh&4O>#su+FWo=nfSgZlyT|Z|F zlHh&V(F@ZTjMB41#1JBE<^|WIkSlvSfn&|mFMj#UKA+kAYk%o4HAq{NQrw#75vNvm z;lUzPh!yro+=rJsEc}zzWP6p^vl_Fu!|S9=bFC1sr{EAl*M*>!sj~#waZH}%8e9`# zCYLYhSC*ze9hFSryq0?pZ)co6oQ*;amXqy3aJDd)tfL8gRNut(&j(vVQ@q?3JLcC2 zn+f@tZ>fIt1e7yhSY8GzT(5=6?II8@&L!;677ws}&dK=UdGjOBJIiLTN#zr~m0N8D zdM}0ba7}JMgYV1dH)mgeb914&!86}_XLIoW+nc?2-`t#d?Q%2T3D_;q&B%d1(jbshKVz}5b@HkeA#=qB6OFNe`LWF0a4kg76EOy> zf}9*7eKH*H#Y>qB6AnH=;C>rrP(kxpd(me?_~F{I-;xqeM`wy6sHROk=6G-FnGzZ` zT|Ho)`MBDp+=eGAOD2dqp-J@ z!w`on+JI`V_mek8^?vt<(8%=&=uXN5!@ z^=)C}>6qk27CY4GJ}Y6nJWtQJaX+gg%Tt@Lg0!e_bjXMX_ohXmZNm^ z3nda9q(mM)?#O|st$Ve&3cl_dmT^rdu@4SoS(>CF?oL zAsjv_wEFx~C+fcU&gSqh{r2Yc2k&n7-hV4e{(p0JUQLoF*Lluz?aj0q)8ozV&SEV< z!jm8%5OS2nPy}T{cls&(BML<@LU+6oNl6ikph%DqKrEKPE|=I@H{SO2wD+dE^gM4? z&CY`0jlP+$tLigpP9C2pPcrA`B27(MiO*A{mk?k)j4&tgSY^T+A+)mzGtrtO#JK@r zhwTURC+#*GEGzN|7PO2MPpWDZ_Ql zWZcp#9zy_=VDF=MM0FD=*z>(bS% z%g@PtPpw}AHe8pd7a)p(pHXb;h{dX-Z3!}=AT4tV-E7`_F!yoiWE8OCvkZxQ&XK_x z!HKHCiI1Diy&SNd;^e6_abIsS_vKvJHl777D_y(k7v-qnx$TO|ohiLU`XhLUI3`|& z(STRFiJX5mXP{Qw2rlq3;3M6s*y(EC1*Z>|Hi7AO>VRbFr(-7lg5xvL2z@Xc^#)e8 zW8Xsg5l7{F!dR`_fD0Fh>W1H8?9G?~xM>@_oab8bELP{kL*ZHQnP~*AZoi~q0moF@ zT4v~AN&tHh*Bllx?T7-Ru;J7NS5F6$v7z7eK0+uFc(g->RM)L|bHKP*xB8EYf&kQ_ z(IWvAV|h4=!3c40phy50BR4I}d*bkOK_I?J8=OHL%cV4Gp$^^?#rZAMw~bLu6bStG ze!a^Fhedb>ulOx5&cSnvL-E!lN;AAj7-@y7G=aFlRwIIT^H|E~S(~Fv($i$M$^v^q zQzDEV6(B&J_Ctj&NT>i9F28vHZ_Cf$zrk9Zv*k;#TrF?E@ul+7jT_~icYcNof>iKq z-|+n(d?&kf{^W0d#yd5! zy!-x#5ORmj+$IRAo+i3zoh_$fEHvolm#&n5{!hPKrunW#V-SF|HqJjdDc>=|ig$&Y zb8!$I68HOPIPQ+N{nL!F}FmMMe*QX3!i>{>#jaY?G**oA8=i`YOB4+UlA1 zOhVtsM=!E%`ZWEAm|>!>FVGKc$hiG-9?C_oru!K|QE<;9n%r+MEd`-OD%}tg)G$_> zYns&75?!W6f^cu3-8ONn9k8f$9pSUZ+MXej%#Q3L2*_+O&9(p&XxAfb?ANBb9k3Hp zE*-3`2Eik3A|r=hx?DQ1y;Pc~W{BAyFUO7(08C000HSFxGx8LE4T3#Nk8uLOS_CSL z;+i?Y%G%|#N1N1c4v1dc8v(`VP*Pxw$5ih26-Jmbxj>mfRfb3Vog>rTq-Lr09)gg0 zOSFu=E@hdBhs3WNOva)xRxrTgAu>0O+r;v3XHAVXxw8BWV#5mIeaA)tFJtyv-Ev!t zjfIq?xv2prB>tR`R!9qDJAieVDhx?inu|Cqt?Ocgc<}&a4i>!9b>^C=y1qxGqXB%x zm6SFkkO&d?ur8UF?NXS!kzqs2ir@A|WhZW0@X-a}dOl8_J{`EMu{omiM2&{@Tmuzk zIMS#}tgH&?RAD4S*$i+kT04yo9O?5DaxU(Go2PNbnFdM0IE*EKf`qm^tby7^Nj0*r zNhF_Ey={dHP&(s8S|@h{cB=~P94Zk`V24^}`c2>Hs=JzYp>?;304pRF$(U!PGk(z? zEw2qcG-4R?2Kq;k+HPr4K0%!>-p-sP<<+1B1Pkxgpcl%qZ79%g@1TI_NGDt#Y{nS2qh@U>ifJ}%YZ)#he3Hh zpMRF`+bFGoATX%HFjaUV_36>#!L+3|lJ5eJ|2b>}&-iYHTHf*wfD?8cK&b!OZ*OXb z4*BPJRSuWdJpXR{Q2+rs2q*#Ez4y5M_^0pjLKlnXM1;eQ8=scH{EPpK8|nm1n@M1p z{{zKmJ)c zF+W$%pI>0kp#{RPmb>>Kmq&|FS=X~&zW@F2WRi4m7i}8MP)k%BawrubjY2G%Nw202_vxKY|z@JbqM8Ei9CiFeTud zQ{VqG>x%svy75oyKkAOI#P zM8U665_zlNUF(AvIISZGb=w|&w8B7_roz}mv~n(EjkyUxK}a|mrkP7Qg#g-tp>J=R zS8XkV2nx!aL)Pi=?iRD$M_MmfN8|2y6AHCdkc*&%o_X59nPG@(j8JIEGXVg{SeeJT zPmdVq9(}>zQM#MBZKxXjlfXGEyH;)1XmCj3h2z^@|&A0Ls&uW zD_B66&td@)_6QzCK+t)GkW9@nsRxRInirGiMv67&nAbTMI4A9p=ea;p zSC&G^6h6m2;7>4xma}f&^jGGUxi;{Imz?hzq;FCPBuUo!s@3=5r7^wuvkZqS@L}3mNU=@r{k;%NT^jJlr94R;ME&8uQ zr#?av^wZYzW}l#f=F#BQ&Ix3pF2qrUaU1ub{Ka-M!u(@y3~!GL7=X*!(5&F}Q)?iV zD1^Wrrw@dVU3EG`9ugrW{-k8S2p0jzGb%ieSA;a55stQ%XXF_fAIh*Cg-xVrp5q;H z8GIT9B6wfi92_abAGO1IUkllgbH^ax9UB|cKd3hNVSB7Ig9of)HTR#h+<_3Sb@;vo zQ6>=ct^CgC;JYyOj`(4(YT3fr@AbFB8o;#B5=S5et%PCD+1XPdM6dkC4}Z*#s-N<` zU4HNPzE{5b)vpj#Fv6ZNtY~H}$@S~6mmmD#dzql!#WnZV8?Uhe-cQO0H$E%BtpDx9^t!`bYmQKyv%#B@!Xty>$<3 zV>0=j&MurnOWGy>)FU)6ecVIk!ubo)KF^;&j}T;|Ihac3I&hQO*I`_Pa&`sI!-o$M zsJa8trpSJ9=kA?6BVdgCKR}r9H9{^-jrZKZEv6|%rW-=SaY9ugD0A3#J8!HFSDq^z zo#1qk#hF+QG9YP)YoieIDsveU_iz{|bvnNVG6|y$JcH@G9wA=FI77xC2bl)td0`1a zL3X0v5D13vZsOvYBiLgGZFLyp#qMNX4lWlW#<~P_SZ?N~D7!ZJ=l@90Y-2^OPlMoqFifa3P~> z#i*F^&`pL0AGkSRg)UBi4TxwUAUg=eG0f9L7|Ahbb=e?*sLO~eKT~H)ha7|v{}fCz z1>Hfq=v2;RfD*qxa8pxx#$^XC?DE~UW4fH(&LP$@mVS6L^u5gLnfh|p>< z77AwF@VdzrKIULMK=E+CNJY(lDIA>#ay;DvW%21^vW(Q+ZEW3w5_^1Fc$>AOjdjT` z!zet$%)?FaT1_k_6s;aEX)U-Fc6>IIOGgGvN8F&$WgQA3Pn8YXxfrDq9E;wv6a>Jj z0SxwO=N4rT5zNv<=s2%aC({)O2rGgEfrOvK$x?NTN^JEsR7fNG7H`)AxgD5|Y|W2J-Vk%1@9)fv9kbU`M(c zMI_?H8eCp2yI2NY_G2=FtAmSUj77nRUDE!LvD|tS074luYlV*GC1W-kp>u3wSVt{{ zNOnNR&1T-VU9?kE)|knF7+DtnA;cR5LLjho*VVr94!1{0uQP$aew5E)tRjVh+B;|s zQsYJhLe4uGlu+2pLl;~xlQI?~2Kq0t3tvwz)4%<$kh?F@AkuX=~|Q-Tfc6_ z;|^`7oCJC#6FJ{;>zV?nt8f9Q%+bgrw8td7b@_v($D*U>Wr?R&{G2X$ zUjFQGY^e97Ed_7{qxfB~ z`zb!=sFzYsSQg(bx0akQzveqn`0(@EC1kHDgecrwY70h5Iq~}L&))|aUAACol>hJt z|F-<6|M>697VaHg4Qg$6KJBnm{f?=@$$Xs@A7U`v(m*r5gS#q#1Ayk6TV;j(Pygl} z=5Fre!Z=kHu~ZfpAEQujmNTziU@mDo!3=-?=ReBx=gysjC@RxjA%&0mr$B-7+H0>f zH?>y&_HW;3l5@Je`r4P`>$hR1{1Id;MCE+&%a6)U+<<@Z2fv>!zSUT7-nmnHzx*Z4 z*@2VQ1r`h>M8Y5nQYVF7W8nOOle7BsC0-Zqde~P}`U_VzQNz2Z@oiuK(sdTSu^lw7 zGLgbD)Loz@C{n5kD%5KDwoJhKg(Dw4TQ!o5NXEsBmSI`8YZ#Y_3-`Ka`(z7BC!bfA zm&?iw3wsgZQi43)&=HN+P4P0`Kn-5BPLg+M;%uLXr z-8t_iydZY|Dei;p1XJ{w(AJu3IyWIR?j!i;J(n~GSNS4l00A7YEk;_!I z6tt3diF!cSPm>JCHe>kWlV=E^`EvEzW#&is%6i|LkYQV%Tdk|bs(jQjg`{PgjBB0u zQK_ibZiJz@My3e&g>vqtp?c5wCxn_lqI02qJ+`&nXPXSH5tTlz3O`+R*;Jz-Bek@k z-KS?kZ9J)I`ihWcDtvVD*e;o=3X{h=xz(JvF%R4fF0=XBS*#R7rQro;%vM-CUe1yE zB|;lqmx)?lBHW;RnX~r>;pskX0EgRgtT7+lY&-_GE+^2XZ6^5%=8#9>3s2)(cf1t- zZooJ+G){X6@dhSR>hdztl8n2}SE1BZsdq!g(tfLT#N9=|EIWyMX^XgJaDe=GS9d;^ zoZFfVgwVe92J_eYaKtQ6r83Nzm!!pncJsdU=(y6$(qch=EC-&Cu(6dg3Ep+Qg{-{R zd-b#=e%laEaU~P~wvT73RZd;tpNfp_aiMe~9uY*4P>*yJoFLV+247feRNemdlqeQ{Eib)dGlgzP$79Phs3-AHdxp z;GO4iP0D~!B_4s{KqR{@?eMp*Fa@FOIwT1ZPfgC#wyGWJryXMf=L`(gXe8GSdCm5y zK}1`n3US5vKFuUY{On6ON|g*N__ zEzY|T;7ho>PEF(XV!lU5SdaW`Bg|Q}vA~X)&m&wXjJKzCLqgdeFz>O3r@hYo6&BSJ z;pV!WDFoDLmq;_VV?Rd2pCWnZIOiCX%EQ31Mc|2(&oq>_(e~vHOb^_z(~ISBc#(Qx z-Y^aqltwG%Q-SVw>qEe?Nxu^TWj}-7mSaCF+(mfHPNb1v`3Hb`lux7O(4Kp^g%1gc ziF*(vcgI!YvWS|)m2-eKNMOq*LR!nE>$V#DM!+pCUKuwvF(wp?;-RZcCCfpvNixx_ z&ESXD!Y(dJ8KIhD@LAyy0VU(^qF87N?V`Pt2a()z(vao(Zd|U^Q?1@Uj#07W?x2gS zy6MC{k1!Azr2s6Yhj^qT$FMW=^^aYBjGom*Xp25qnbBQTa`RffmGxrGJ7_@S*Qi_5@& z8-2&tgA+uYcKANUF3s-DyU9`j7liMDQ!a={6lGj>yE>O8<96Ln*8R|515a|$H;3OH zjQ4@fHrC%LN@kMpQja*O6H$SwC&aPH$#oSIX;kJN7k%&vC4sVIp`+iY7WxlRpam5H z1U~P`*W{;K;OucW;LJhea{^RVTL;lU9;O8>kc zJ_`;;*3d`sfP&~Jsv{Le2-!HbK_}0h96WoL=p`U<59D`C<4->MtX#cxp-i4)QW?f~ z@xrazUVi$spHmQ81e(OeXrnwMy~+`3S}ZRv20O}k8IX)x0=atiO1b{Z zb&%}@zlYJP*2;T-_e+p{8^#VZWB5*xddIz5Y+Hp$1)#t;+O85Xx413QSgtTolMvA* zUh7S*Z22pq@ zCO70jS2*ZjoB0L?*k^Pfp>viM;I_59S!PMMG|k+Lnm3T4e31_A79==qxYOzuX;83Q z$i>#feRlkKt&A?S7tcD3Vv#u?#$b%h$?jU)!7A;ZoGC|?H$qg}IOi}f+4kxALKq%R zfxsx&d7;95QEvjjJeuG>YE%!VVmgx^?iLs3DlBD&3XK*4C{1upm^O?{%0yk;6ez;tUv0p2(~ac)irr6^|ZiQ01~ae4O8lJ4bBjTLS9TPKwP8XNDssp zUsO7@NCl`h0iZDYU0jaVDL##kR*T=;5jylkw`N>fT+|J!%WA~n09;Z=b}0nhN6V0H z-NjEAAMp(B$JdpyhMsf-)%8MsCPv+{AZUyAM(Kj#MF>KJS|)>Sz{S}REmok(Wd)dP zbF_v{dg>lW3ci%Xy$Qz9ECu3NBI;y>z)4Sr^EKiI9nUyMBc`unp{_}lI_J6+&Ssl7 zd%D8GwLapruvp(%Esr0=@=;ihaIFd(%cMHWp`W<7blX#H%GLS|-iP^e-T6HPicy&d zz+R!M;M5ZH9B11Xt+!=79?rqG;48uhNFju2cw5d}aE!7lzP9%Y^g66)T?qT7WxxCmQ3(3Pl=bDyVu#yUb>_))gPLt$}< z@*QPcIuM`aA>u60nO)lo{G=E#T*m7?1q^+(9I2CcXhKe@RST$wM1!w9EAx)B+vjO6 zuNWq(xAIqUf~rv-oGOrKSe8nMX9OHYd%5zHS`}~Po(@N0THVsX)(9UD+vIiloTt3o zOAJih%Nw7K(D`Ysinm#8J_IV)v$OGA+d`k<+`FxLWo6lCtl6$ETi8b z;!A;`J8;0jZMOpu@G@|A)X>}G;~HckBX#|e+J^xbV+apJLvdpyp8FkYVZQ~;W6-yf=(ee^e45=OnB8T5Ct1B94 zh3Q6eaMiNW0%@lRBtm$aM#%EO)xa%siU)N6rLPc&>pfzM(-&O{kC@LJ)^cHv$WVAg zcn@$T?rm(x#kPstXzS5ZX<+q~Wi|Fu*m}V$P@IR@q~u&tWd0b^UVb zed%gxojg(6xIx;u{j#Qq{9ZCPfC7<0)G7>)83f;gh}{O^2zSTc{Y5gPGw*~}Jc`@S zMWsi$`i=>&A3i%5jWQfs<^h~Tkn}}Yhu4#MQ7vrK_HLGaaBKJPKPlzTgVG|re+W*I z2r{)@n7tVv4qUsYi-p%RkqgeDeaJAWnoS#Y6j{g(*oD(x*~JC(Jt`Qd7DKxdF;;5Lz}MmllH(b z;2^GLQ7v_dPhr@=+9evjC<@Lqiq}F2cyWrBx|bDZHA6f`G@gLjnK>42zsB6rGVc&I z2`*HAA}t#9z%mLfbm4abB}{sCVX!o6z>=R~Sz1WYr|okrqy@bU@(-2CGi22m8rop< z%5~^jcRMu7I~^G>32u*20^;t)s^3SjxpllO-*>aAA%m+TEK`k#LC(mb3ZihJ;|zVp z0eXP50A+)JD%bl6Q56TY51_DvKCkcJ>ckwqZa!2oo8Pe`w@_bCujO~_g`>m~Xj`fQR@et@*hyFe)hDVSqU zLFIPZ3Qmb}f+#kJ#D2sIvK+o!mYQ3bngdP8?3GOTxn{+SG6e;u6R`V-2qEqZ0~ZkM zR#?U@Ha5CkPLV9qh$+LmH|YDO!kwIJM~)^ z6mrJ7#ljGLplwD4=A0BLg}?_m585n+g%R*xU=MKu=XA`nurdm}tCoAX`bgcg&)idk zG(JNF1Guoc1!XH%VsWDn9}@A@!1d^&Wy{h1w5M=FAQ)^CM#*>t{=iyBpysLe8U-g+ z)7U-%D{K`&<_L6D49d_2lXW~23)dKqL~E@p?1>aLiqw3ClRFc!7z~RK0p@AD$zW1X zCV^>#ZZ#D&8IjDODm;}g)g*1Rc;J0;O8ikHuGS<%oAxUxJHT7lV1j9wuZp4oba*Y# zSeEU!daWUEROTmc3G&Kt!ldZ8T-0}+1Krr@F;BCYKnRCNAvw;vuT9o%xrWJwwqb0P zw8ch*E)d>wVQDNut#|6(EY(X{PLgo646F|m3w$!MFqOTz1=`r zLg%E7D7Gw;&HSZ;jZ?wx=~1I=b-{6g_UW|{mE-EPf3?`utCE?z`eW&DEvl$OJZnoG z3&&ZU97O8bZ|B8SdZK8Er`(TH!Ltci0cH*0pb%<#+75~|i0s!Lj`NEGMs-6^gV%$b zyi{?4JGAX{yZ|SJpZD{3@W*TY_6r9ApXcf|`}O=i>PVo5IKVS)%{_hg=4O)-x|nZc z?HN|hI?-xlXgXJ5+AFxrZkA7O-N)y8Snk|=RQ}}8{-VsYW@CZ9-;q{p80#CNSYPese;vu|l4qE#1F=zr6bD%jNvJ z3xt60pgEl=AAR&GK?QeVWIN@_1EnARUX{EE53nF015y*vFzq$;&7Gp5H*^xSQrh8XEW#`8pmL> zFf}Q+ZJ0(Vy4FBfof)-ddM<*UnVpN^b^ge5O|>&cB$MM~pW_=H1{tWQiy0imp-jgk zL*_W) zToPF;Jkms0>q42w(=fhS()3?Ell^`sV3yrGi>3RJbzfLBjVH`6k`-M`tg(*U41o&p zc~#1lj^nhb7%lNATr!n538swas|Th3h>KF;%`<3=N85iZYe5^j4$ph5!yBtDcW z7#s@1A>*=xK-PUCAtxIF%tZ@C_!}oVjnHn5N~Nr%h3>c7p&?L5zg-4q$On}?#)kcmRmP(vv74hfh0X> zya^4BPh%OO)J_m&v+`^+!fy{HMa|{-V0uEhrqa$XNmHKk62yy7P9yCw#Yg zPNC{vXk7%8>3kGI+8>rHRhqHeXgueg_`_?$kg)`(GUC?7zX%qYvq+F@w1YZz&802W zV|n65RmS^_ocq-^r=X59aIeE+A(qCG>%Zv%uF#_y^yk)UQ-5UB=qf<1NSaLt&B+HI~i75#jT zR4i}3@oF}mvmqw))CVtd?4e0Ise1n00xq^`5ElyqAZj&TX3pvDw_azi=o?JV(06+jqL_t*CmlM_sbcLlb(DL%Pd(((?es``-#^U@|COLtxZ4g;S zd_QG4o+3rsR9hEU5~T$pBzPH!%*`=`Dzb3XMWXv8aNUI7NCnjK_IHv zN#tr(vK%l81WTetG}az{>|!;S)veMbi^4HN!u4c}L{_a3Wu*)ASYJEu3)`H|?=WA) z1Q&~7f!kBocVWTxZa*&NCMlY3KPgT6GlZr+gqx43Uk=Ct+&_d#?+~iJLO}Q-^HXJJ ztn4A<_Hoa!nu~ujd7hO(ASS! zeP8QZoOA9{deD_@8{)o!E@e#7%!L!DbypmRp=97>1{MCX6&z!qtQ?a!svF&U6&kk3 zPhq14Zu1TqH@AJ+$CalQqj0AS!EqUrTD$>4dO0$`q3aet673#E#2^)iMxhz3qHbM? zm5E9l3M~~|?$bPlm5Q@%Of($NDs+wJQz=j=*bA+*9kO}&o{OHf7=@#JE)C~By$#}l z^p~zPAkwl5pXlX$kxYI-iwX&^E8I+KtkS5WqesNRt2&0-<|q>45HOCg64sW@nCT%( z&;)hJALDYR9Q1%H$g~>MR{BF_I63R`)NzwLvt7S}6o^!Xsy@|(W+pC61%{~q5JNx4tg_{mZEQ1FSq+8*Iy*`Xn> z4L*a#{BCC-8VbeQ;xpU?F-}`R4 zefu_ZI8UgSRo@7VZ+`vDN?YZDRP}V zcQ#rj`aBxX0>bQN1k#m+X*vjIuKxZ%`E9hLjSRed_MAF7RetdOZ%ke68uMi^o=+Wc20v%BM0n7j^2oO6- zfC@B_kx$DF!vt|9NQqhBwL`IR;X(%RDN%GA&SN1&UwY|kX#$HS`nQ2F)>p5)vI-c> z71aH~7eO6R>aJrcp~$2pr8;q%`4K7x#e&S)hztZ?aoY@#RM#VKF(*Pc1+q-HVGJ!8 zx{+_JeJ@w1=GoVWXet)Yoa1F^Ej3~Gppa(pnA=z-0sgbgEf0i(n+5G)FPVXua6Mg%A6 zWg2ezeS~FVP=fSg$hMlHmP_3N8ez`6x?c_5K7o?v9LmKDSKhQ4jxVIbgE7$Z1PU2fnFxGCNo!0?^(oMFA5TiUy$Y0kI}aU)SiqPqGF z!00}g1}H4!Vw6GPnu{`oaOle1@O+Ajj|e2 zq&;v3o?61L-*Ilte(8qWC+y#i5~s;1p@0ZJJLf{V(v@_lRchL=%qz*sL@#NsPaDa6 zPjuY&c87?#Nfg1c^6{silpUk?fD2+o4G28ISO*WrX2)5Ez`Q2(u*-a$k#{4cb8;Sq zhVgX89d~yf2wDaKi77LtA6UAEduJUNFfo1uF^-##nt-8s{ObNe%x_vX0>k-G=|rnY zS{N{AX;(Uz=8d+roK!_Cyyi{2%zq_zo>j<2q2!)$P>4I~gCo`mFL_N*Kr+fOa9&rC zDwGs-9(B%I&StMuOa6*K^|bN<9aq7WIVG;8eS=E-pSCq6`5H~~w^wp-!7eG(9G7}s z{^jXgK3|1ivQBWtzP5KDawp&Q<4-|U9rphL_mIAXQevvxP^IJqTAf<^$S?>7;_tG1 z=`i=_SbS(mwNY-m;Ea4YJi=ANy*BGK3@*^5HhOG=?HNo56s?B_sKqDYBjt}`jyG6X zsULsW$So365_!tp#x!M^K(qq3W&-X`sgqMh~%72Oz0E%;TuO2SRM#Br0*d_ z>Hv;Y?=S%gW(-za(Z%7s#v1cf>MJq<_c&Q+4r&yp(Sabdc^43MP}MA)bd@@7sbJkh(^rEtx^M#_w~dwc6hVCiQ&hQu#she*wH+pIH%VnO!d#5n z!4U~#vkD%qk>S#)$+IGqL@g81H!VXoRfrg%P}9a#!yw?pe*TZGJ{|bv)_gK3# z)xd>u06Yu~!(wRQUK<)C*nmaC$8)S50^aV~G;}ykBoYrvEn=0YW%ujgM?KJpz&Hp2 zZ8!uBVnZ}!f5aceb{D{Y6H92AwIE|4s96}MN!Ins_UNcekqNY}*V|I#kF zcZ#;l1UQAa?mMiZ-r{OGy!)hVetN$g;NHW^Ig(5X3Sb30tsQ zukCRg3Y+B^tKr9z20r4f9t!7KA3nGrtLxg;%gmeJCx}NpU|E8A0sd<3WCW>1e06(^ zXr^3^+nGwWYTUmn3pwp++5vRMAzJc#XUM0oM4to$r)t0$OeG2K|QAWjzod-K4Fkvl0O72Z`>B40M|75v+ z?=ch%EL?X6{Ev@z;8$$dLVIQ=Dd#L68oV`I2u8!fyM#;DoPoHu_^12K4cN@lrT{WB z&_heqg}8Ozj5atHG|pY1%{`Z>J9r2QLO2*V+8iL+T-qa?{3p#QD0KDL>@-+u{&uYC z>j5~Vl?2993{QiT3U6NH1=I~_r~}?gV}7qUe+b8c)i10%HdFM8TqkZsHAljb6 z>C0Nmj!`W9gZ56+lTHm~ql9W%$x`aHygbd`7PoBy<~27QfC!TMIQ@g0Szyv_1* z_?@<;RbJzM`;bX_5v@xn-P3-AWS}nG5=mMD2u&6|i6w&}O^1!lg26NSIYbEOG+K!R zr5i$*ncqz-Vzz2EVv{@WGpFNzHYZ3CKaJ3;NI+xwudjVimkf&vt40d4K%fjSVW9{@ z7N>QFSVc{PH8B-#PGCAg*`vKDSa}a!(WZSu#6h4VwvfOb;0Aey`>G{K7^9?!X(QE= zx*p;c2!@~vXdxsq8$4k^fhMmA>oL#<%((?ZkPhM+L#Qzj zy5TnQldq$(Y0wy*r;v5dD0>ohnZqJnIm812$J;Z&I(tx$lpugWLsmWd&Ep zA;AW#eC~kE3+x$0o77GnA6;@}NJWZbRXtqFW_CT4nFdU>M}}htGfh#T9P-XS+8`o` zy=f2{z)M_l;h)S!hOQ8@jfRfuCQ-i}XqD*|eV{w^fqsDd7A}#hP3m4#L*x?IWD-6r zVN0kQaNIXMnQ;>@)Rs4KL3YT}JUau^ChXlU64uw*ag_F(AhZpg8J?f$NXxMi9x@Z^ z1wCO3wwEyVI{La#DQ z{=g@6uffY`V{_JZNy8*9HiA_eqmeK?g*4Q{cTR_z(|ce9@Rgq+=rd2Ni>^MWurNx_ zh|^;Q26RlK2U{2+WNU2#HE@a>eBlTW;k*2ZVXgEmy>d@wF|IOerYs%~o{3wQm3bqc zb)2Gb@i){6Oy!3zS~qn4b3wsf>!PhWQ%)W8nq7kaaW6cFPXj!3kBZyY#sA>H&p1XA zrWr3=tL0)F;YqY2hjoPp94Fx??s6A_={WytyLC&aB<{H`O4IC(t3;RrVFCj<-uz?S1(GH%e zi##%T+_Q~_&N`{B;7MpX_Z=kRC-ZQxlo@vwje7;+;hpMxR=0CdMGA{e;#(`YfT;!$h`?s9n-- z$LWwAGLLo{S5(Mx$Cn(0%>yjb!&_zV&eOW!mGZPIds>xRL!3hhvI*Q_U;{!Lq69y5 z!y(JEA=(~o+GU8`!r>5M&?0lh2{LrAvAgK5%+U8}s~Vaqd9)-PBMDviR2Ufd!yrMk zjJxmy7tHigPYK7&BGnQX8)dBGo@>S=<}pIs4eoIqn`CD;_0j!%kGPJ)#60Rg%Gd$4 zkN^aPy_S*IfNO2!@7Xg5cuB-j?wDi1ywBK6zG|%Ek2IDb0LrlKW=5BOrdbQ;T+j+B zx5R0cHG?j+p6gslRaB&l%8V+#)^=zip>QHFg_Dd}ddS4JH#nS&@i3%&0-RH!Tp`kN z53Anq&IM_;cvxo`xVX$2cP)}tYpb>mj|A-yowWFT%=zJ1V_ahtfdgYrTL3$F*+pq1 zXB>T+Wr>I`zOVkqo8*GL$6Cfuq6o_?k|)vrF$VIt31ENhj;Ta|ngCTdoQhWFSEwbH zFD;bLtMI5W(dB9ub{T2#Mx5~kCN(<)yp1ujZO-MmrpWoJ@SI=}@S-1}K4WB8{Uc;P zKj6v1VU?o{KesH8TIoG);(4R^94pJEC3(3D9s40JAdLFYgomh z4y>ZgU!~?0n?Kf51xsFd{*DE3i$h^!JEaS-k~ZX%imP70Ms0~CQu2V16z0T~9HTPc|Q9cGWlsb-QpR><@t~Oet8O{s#W=!(%K`wO<5GMeI6AbyWKA3xDpe zJSF5BH{MfH9=U(e8ruhq8d8dT()~MRV9}z1rB*@5&=UW918_cwqyX;RS<$- zG*zq@=5#A(wIIYP2#$W(^#~?Dr4bb-MO;nKBZX2vxFPQ732;7TncYL#!y=2AP2@SW zPi6_2t_;9=ALoH86R}Ljnl|{CnkZjb^PRe5*($h03w(0T_91$d_ao|Bo!$&f3qQ|yxRZ3)V>LCK6ULR^$e9sCc-f+EMS0_K+8ue zw2d`{P_N7q(Rr543c^!GKt)moO}MD1%72_9FawLakiuk7*PNRnrcwd!nDt>oo#8XW z0_DXv)-e(Dv|eQ34u@@p`BRtpgx&)l5QNYdLSE<1;D)0ai-P+6H#qzzzs%|P+^0DL zn0IqDi+wWh(sM8L?O6@-2YN89T0`S{ln^l$%$cQZcq0zzoZbR!Hv2P;A1ia*x+ zt$_28h$hzvv|4B=45IEPi9wB7+Q^BfX2xcPjNzJD_!a>~;~+4#Cxy@fb4B|gkjNij zB=rLEz}r6fy#e9sZZj*c=CB>Czy`n}j!NipkMTS(2GP(4KpGi>$Yh)BNA?mzdp6F$ z)o=|E07oENf>dKdO$kExnA;UQF=`^zF|8XdL6U+`e@aD`ty%FR~u!-Wi>QflnfI=^q5%q%2(p9xa6NF)p`uT$j6expvD0mKf9Z zaVr?As#~^)Hrr$(*^T!aP7slLg-%ieWF%qq&27sR)r7k&TSnQ2!rP{9fe76ac>>?U zFz%8=v`!h|9`JtHTPsg{E8qm$X>X#;_fC-Un=x>}Y`5Ei_gy6_MNa;*ni|}uJ$&a< zaK!m1=X`KRV*Rj103mXlgz1i)o-R|YZ<;rxe1@c+(<5bb^_Y1JCcSZ8!tO;3aJS}J z+eP?GaE>#b6U==gl5OzgADn%FdIxwo&opqCXmLn*;=*9^--WV=tmWEb$$`7uPT?w+ zHq4|hF8geq6Qy4Imz^nrpX|)}**ooIYeQI-Ot5-p;Y@k&z4ywUJIo>Se3V3lq?=o66(ow4-%t|M3v3s7TR;S)h6mC3v}@2Fl`GyfupoV>e1~Pg=f3 z;#v6|Fo)+w!Qz=Zc0OOvY8_E2bgYspsKi0}W7@_o*H-zQv=KqdXM|Bcd8hv8T5Yh; zd9)2b907PTVl_ems?dqX0a9(SMnmK&%`xUnn0yCG)YhH6uc`HGhcs{PxLRE_Od6v= z&{b#IGHA6Db37?vM(A)BV8IZE(QYKp#JvMF@2gSOXd#nedaVi;T^u%EtxDkpl<0=E0)}0Xx6lUi#1qgglI56w(bB;?f`-sb#7#g zIjcz^Lgd^&%y*aZ8bR1*uNd4fW23lnSR>NFUD05nX~Lv=E+!S(5o~)!8X+J)@lW`3 zstvawz6OfO@zdpU{Mr4|WG<+qFM>zJ33Gbs!XRKDVSt4L3}(CTmI~9+dV(<2fIGNc zdaAI(o<7920**>N$|{Z7L*~ug8sbpF%9^7|a)^zZ!i7{%Jr>j+!Q77HPSq_|*G|YE zLTn;|_yG>ZV(Am4V<7={@vDT8zy=F)~dm5B}H{VFXN| z2L;XwYvJbS=UCQomb6i9WAfkuLJ9aN_-r?INZ)bMG2UwP5g4>n#v$Iug%)@L1Hfgy zxt4l#RVg?stph$$fVx><h>%Xz_CZ$jHlH4jf5pSvmO@T+BHP5f0H<=Q|W=Luj!Ipt#dCw?G{CBw2!J)$mS|zf28Gf~zh7 znMKub;AH_wn8cd$iO{9eImN36~v$niJBp|BHo+IOBpg3xE`o)z&1Y)}GYA+waa(1m9YKX~hLDX2Qe#x7c3&3Ey9yVswP>$| z>D)+w!1wHBqJ>0Tj!1raM2^A(Lh`kAI;XIv<|mnehOyJmeO^mGFD!2r1zjqN4k0bX z6UAilTuW#-LPwzw%7Av@34O_~qx4sL8fc6XAYc*%bfq$cJ``XE;Dh*VTlrpHMhFka z#c@)RP(W;Muz(d;p=(KoP~v=6tu+fZ#gAGbb=Yp}U<`TBZ5m%7AGUZMB`!uspzw^$Phpls`}DY#qE^WzD1G;Cdh7X8T+Ko0M0$;1BVF zxIw3Mnn`);(Q=jMMZ^tdl#xe=qZRKv4*KX}G9p;y^o1Jhlxz;7$=YeR4p4BBfG3Jd27U) zVV%NQO$Uy^AY&mB25yHpVS<19XMfKAM8C*-pfUX1;0NV_tUMIIV zhnct-_B2|V*`?h&;qD#soUzVi!mXQuk4Ua{DD#t%IG|Zn#=uD&hG$l0#yknXoj6^A z$nM{~Sw8yUgR;i_4?Hbl+4a8K8^|gW^pQpZY%jwoZJ*qgadnIB3Hmz>(;tF3XV^e& zO7|t}JL=p9&sjK{@F9%E6ewN8CK0GDtf<;uVaMs9!6!`2*rMDf!3YhLin6e@cZUU~ zHy@V0kM5Rz!m68OaBv#}>!3#k=oUnEnIl)-{16FcX@fy8RzRt-lMJ!eLYMh;iQYNJ zmDR)Aaq(&I6rtp&aXp^JvOY6e4rYhT{#di@5-_tvbe!pVT=mY|2qXW}P;g`qW*(Rb zpMG636XB*-E^*h;R$3uE(@j4s-tZH+$^bP|u?#u12BMfyz6?)hR<{c0ArA_XIa!8Q zwE;2Com$cuF!j1#hJmJ8HFDrV`HrLfL%x{&ca)vB0DIdh9x6Pu;UfK&2I})wXjq2A z!=$+`#$IO*QO|=ooOupDRj?BF&2{@WU_v(C9@w{72-eN$*iQRzxwh5cGCSQk&asLA zzGwxS!e349hPn~xU|v!>x$O9;&=IG6nyKIU#ExUh zQ?gZ!2da%A;#q)=P{8%I4imXe63Wx8;g}}Nf%6u+2f&+h@BR~_Rd4~3ec%j>S#_fU zVO}P}287Tmpl#7O+y!*a%*Twkdxta$>okf-x0`Od_{N#gHXE_bKgu%?*8!KX31uoc#w7^c@N(BtxK=>Tkw__m0@g?iGlBqcA)!p5!?wu|Xp@;!tsdW*nqr@n z`I8L3%z%E;F|CNoRM3(DRux{NLp?0Rqy7ca7_?pBBtsDqI%rxBoGutwLx-WjRPsEC zRtHVwgot6d)9e^&wAaJOi-GUi^B02{u5)?(;C^{{`*vAZ;{)d75SQ~qT6T_IPTDMj z2rI2P_cj`$O&T!n?WDzG^wya+#_zo$09z83ECMjh-&oEvQ z2gAHeP=aY$AQ$?irb&BYAWRzpGwPua%`NUh3|d$clE+|cbD54rqt@wXl%{;EL?@g8 zuy;7UFAkvq$RxPrSUd5awLOfDhd7e}7pgMEx=rwfYnfcgX=cfKEEim~9h4Q#Jk5rIVg+hZ9`4)E${a!;Fm?r_^OLJA3ovv0DIz1S!=RhWKxDe& zU78uDY9B1$`m4vl4sa2;1lJ?2eZdAe-=YwzOi+4Z?O^#k*9rzWSo8rQFaH+?w6*q}zx)(i zRs6gtTI3U8N_+7NNRvFJ5OVG^Pm&4{$5;Z{h<3IkN<%7TbuuM)(m$%-$Uaq}#wS0rs?{B>E61ktUmO9B^)$hU{!*<^Km_5^{6o;rCNp|?=J_3hupGTSZ} zFI`N!AM1VekdS0DMQgT43xipiZDDrybUM37G*%Y2u|DS!NiI#(Gr|1MBrEyd-9SPS z7Wyxp%Wxs~seWj`PU zjuYqG%=hdf$aIvTCiIaS7yt|fi~r*H00!m`%r3BusV*S%{0MUi$srYf;)Lx9Bax^$ zWmFRE=M%yT8aa~!Q!U*!Y@^^O^I$xuma2vy_pSVsL%I^SmhBF;hcG&Nzzr5(!?@k1 z;N;08JP0e`GeIVdo!67j1~`RDQI|MmS&qH9=B9DOjvxPT>BQ`4J<_|Jq(h8TC6Vez?u;b z)1;13t!AuT_Zf12)%}1>*OLY3^l1o-)vOL$KD#K4M~tN|Kw&-Ld%{0-O8wGB9gDuA zB5k@rQ)>~+-67Pn@V7bpoG!R@=~6P7o0_ZL`79oh4HmE){Wk_LP)Tu9$8p-KN5Mi4 z;6d3kBf<|nLW6TzMi<4Lr#Yo_+Q>DP4G%2|g`#i?W975*Qt$?j>}Utq=udbmQ*Jqd!%F}2XNhtKD{o#!JE zRkTumihuqm&-Z`jzU6Sdc)i}X&9;rsrj3+WQHZvJ2V7Se<*9x@f=3E3+Tf9(H-6g( zr&!v%SQD-UmTAchpke|L7#Jq=d-`_!(t8}ua~9Xf)RZft%^5d|mNg5LH=POb`)n+= z1EJl%^MqB~k0L~D$j{z+7lL51A=<(|n^u|nj zte=hY!@vG{tPq94B2hGpy``iQT0pQ(O`HHorW1i!$?&@>gN3ONu^@JwIg{OI&luRP zn3T>x8A2T`1Oj730>r_eAdv_N>;|T@E&zqLOf~M6xFZK|eEyl?;62@CYDK1*@$6u= z0rGNyMYYd5845!9R0a?YGz`M=WKccCg?<}oNX&oTPECYKYafCUd1-?JX@_^#80$8c z;3&dq0%0RxK9JC;uXG5;KtLRlo6Uru3Z({Cli9P|WU6RQ@qL02Ync!2Kw6gug3{b@ z$B$Ra0b_sk@LB2cehc?pO|2uMRm8NhAPn!*?mMnP|x0gRWvz{7(0k)?gYk1NDFBcParlA*%LUC(1CjZ75tt^!M@A`^qG zE3@@IVH!e`m^|xWVa?-|itwWkF3R>(LU-;4hY3s%e36i7O9O=~PxG^drPjjAGlJ8h zTQfTcbmjtX*Nnxr2H_{*27GYwvEv@s6XmPn+7jKlbz70@VzHMB$7;pfZiE))xNb=6 zKzy7=8I*YqqU0zjJ&H!o7*?i4+1A(96=+9!##2TDZ2aMG-E;QWb_x|OKtRbMbJOZ) zj*;$?WJSAhckIpX&bW!OG1%9!;|*mke^%)lzJcaDRCNGn6- zQ@rTgR9gj4kyab^7{2fq3}EJ)v~@=o^}4}k@8-= zn6`0&Ps?x~$nTDwF3V~aeg4Adby62~=dfSUhJi@ZYI_f$n-fVPByl?4roe!j5?NLE zKcPcS^v)*Q1P`>^6Um8nlH6@4$++AiEPH>SJ>QvlegFNNayk;s@=U%f~!xN}LZ^Uk{; zU`{_P-}mCyg0p1u_{eXE?0H8KkoTjGGuILE8?;F}`NTRX=POVbP>*3Zh;7Q>!o! z!{uiXc5^J~JYYUYfprW4jv=&NyR-NBN!erTj3)WohUTZsh=C!@@3rUHR+(UwV;E7~ zHX;jS+atsE5iZ*UqT;em1M7o2C>tof5FiNJ$8B&`Rz>|FA24+e%)MLoVO~uaDI$0Z z)=zhGs2nJK2tvSvnz<>n3yhHE+Ho*&fV;T)C=h0*yU$%SBV54YZXXuHQ@-Y$if#=9 zKia~Mt7@t=0KBeaK*5!$ER(~(IVnTt>o1vcgcb~^i%`%7BFw#`>s8j_Tw;^xJ?mCU zk+~VTk#s=_A~pO5E~#a3Zx(pY&MpvYZ`P2ytFSI+8NBbM?Z8MzE^}2#xT~-iiXE$qy>(l&8U2-UVAgyb1q za}?E~cp(fr(PY$>fCHc5)^j050dDghNb`;~J+MTao3ZQ{j|xxbLFFAB14}%-AXg|W zLaizSDkybbrsG}5GmrKE^lN_clBn>7!>)MH1>i3=dxc&CizvMPHhVupN+peUD+sGA z&&TN(Ldf_1Y$x;+L^jux+FLXoG}9i|fqSqk;UbCc0D5RlV?gJ`yW!e)$8{IOvfcCJ5&epF^wUm6Ui57<|Qi>t+xS)2>oXgFq^wnH)b8HcLns>w+7 z{mS{2@CT>mii}Ru4%42ju;&@m)L4;O1=QeHVU$x?AIHouAOj#3ECtfPbQei-2~xwR zK?mk}5Y~IRDH~WjjXCoExu+0q6~0FZu0sMyb{~^&2dilqYq-tapF66$Sk^_6KBvws zx{5(!%pqpWfJmFn`LqmF!Tr`_vFRRyW}l6R_OaF!7Pd^L)JD>{UlLu#Uyu6*hEz+% z8smBxK38&3xAhsYq4umyP*|B3D#)3K5FTn53K8!6oEF7^NW~+|7vHOEikEm!Z5}l~ z3}pmYwc{+Ka>7`+%itwG3w2C{xeGmwI5PuD(_oJQT>*IEWi#TrkgG<0hW}CS#;9^@Nh=gSjxz6d-H9o+VYqrg?f?S~mm^f`P@Ik@n zzF|$~0}UAPS=aBVSn0yyMud`d<``8A(u(T1IBY6oagB3L_kCRiTXCJIG6sn%<+DvEL4ijl;71v&A}^d-v~`t5>fj8ZZ89%;odv&tY95NFYi#`5NK8c)Q-G|ob@4C>7d!gdnOrqcL9O;N>2OR-FN4X^?_2%x;$Q9u*b=hI z634SpRm)3DRShBVb`@S(gT0HOdw z59brP0NS-DV4PT>%}FgEqTJ9@_wcdpb1Ed%dNXGLuS(x!GBQZYwu$IQIV5Uf)&CKA zMB4*q613K(f@l}FZUY=?sW34%x?-!StZ+8RnUPrW#Z!U9S0|#?hNTBu!F3sQ)}H`d zuSG*=aGk%&!S@UspBWnKmnnHL22B?BnxD{(8;$%_2${M@i%6yz`r;ixP5*TtDHIfD zwG3%>UxrU5(qETghbF)dTqwVdwXbIH+>kjPrB8F$Y2`m2dc=GU_~qOoV^xJtwXl=O zR3yy_E*R|ueLAedSC>@PY+<;#aT9!lWg~4_PGID`5lWCW=NyxK!g7b9FZ&`P9HL}+ z-9tsT;4aI*e#l5DM7{i?r^Gf1cCP7ccj5g2sf* z_!GeUC#6xh^?F}g^rH_qKJB0U#6x$d$Dsc96k($in4@D1mdq+9t(}GtoTL_!J=*w4 zhlpw$Vo_tOgUdujQfp&HcsPNR%H+jD#Q{Wo5c>Pz-lOuTfAT-V%%`Vkc$R!;ruawO z(sau@0S3_pdYdfv++;^jcQUlR8a`-e7F97I^ah;t% ze>QOW*T46>Wfj5Xq@7zWJU}Db;P)G^zfmqwgb|d-Fx-76`*%pmG=9Jid8WZ<{Yr=NaJ>#(8!fORZVP64On`|N zj7aAkjPom_+#hjn$alyz9UO#+k0|pHOQ_3O8SQoq!I*?0i%k(rSF3!$mtZ17v}kd+!i=RaX61dP0jR&2$>n2)&SxEH1g3}tY_wLx^|W47O( zoMXF@1+uX#aDcB`zPv)KM+Ta@|pR&3op3 z%CkRws%#y_rBfrnWF98v-9Oky2t8$gt<$)Trpsv}wzk-+WM%akA-&8KQQsk(5Jowa zdC?D`6l=%D-AvHYZU%(Y&|b&PzyxtrhE~@^5jjTC!_WqT4kgEkxr^-Gb&q*iw;j*> z6cN{)N+qR+fl>E13W&Q68{A{)ZFTik#Ssu-8899)YnY#FojT5;K&M($u3=N~*;i>z z7}gc}E?`GNgh6)6At-ao`j+51!4dSc3UtPg@l>EFEX|xjfxy5qU`#*&0|#go4Ho}x z2dxJmW$H3#nenp~GAod!;S?^(QH3$ItS}fynR1?JO)FpebWCvxxR}_0iw%Np_9Gnd z3OS0D)plM|!7q^HQQ|_x5Y#A+Ao%&4Ods+z-M_lzT*NNE+8);|IzLqV3>^S3d9LlR zc|7HvW`d^@>Q897xXtgRRpOdI6_mPI6C}oO;V$bmlT1s+0gIDvQ3SMUQPkmb3g@4X zX_xT%)%hEGmBX>+|35gYb*2#Ia6I}CiRTJ-+vE}B1PZ7^NTCY%a%?DgU@1kR0zYU3 z?l=H$iWE1Wvvif=~Amx*k7ZU;x8%_jfiUNH^D)GY@cqsJW-@#iX}+$j+?uC!g8p0L#dl zQMRYhrLw`6(}NAfv}SbK8Sy7Wa&`BK<}}QPux2U}u+O2-w|w^+?NsQvR>@RFhMYSW z(L;~{*!m>!?SIQ}2PH@Y{B<{sz|eeOU%RlkO(BkqZLL>=7?e^A;ji`E1U@BdPu)Yd zU*yQnt0(|QC4nz6gHG8ptl5ZKQ>U=Ys;;nAG}sPXXw1@r+diM$yt2o59#Vg|16w6xt&8Q; z0vAV|g9ABrxyi&-5=8FMp@eUz(;z+sCg1(6-~HkP0Y{!yC_4`0to>>?*UGv|5Ucoy z*}|ejU_f>j1zwgbfhdTgky1{W41JTqNU+DusnuvQZi=G)!#Z@CT87oj#KYLQ62U?F zG6M7ZRc)O%MXCaOv_dz5bGwrnf}H`P!Um~bWX?YB`4TYMf}>O4uze#U6m~QjWA6jQrupLC@)dO z5Jq)jad{bb4z$KeM&2+fL*m8MeYul!Ni{Q8473~q^E`L5Dn`~0*_+bM?<2A}_~ z0*OK7eiUop_gT*Nuv{JCv5f|1POF3_2P?#kKqdg*#&xxf+l4-4l7IQ>GU3v0X>e5L zXHS%qXmU=5+ClX{*QU54d7S`+i{~zv-~QG&60iU1$nEkz!30X?edZu?B777?Mi{x* z2+*PnhCqOfw54mlDSn(H`c1$39>PW;bWEC<)n{xvKO*|>6*k%X z8k>TS#-e!l=QqkGf>S8kcL{imiPI6ZqZQ^g8Vs(3*oohI1dVZqN!@iUw^bMe>svC{ zBY=P1A+bmxx*$Prz^3F6A#p8$fALiZj}i2e{S2J>blyOBi|IooA}vjsjDuBQ_r(;~ z|J^UNk2DnqEHp-wQZuiUpHAo#fWRAWrEWT#hM~?Nh+)sxIfOYf4xy|-jE6)Jb#N)_ z^KKKsV5FCmy5SVGiB8p%b^`R^Mg(8h>LB2WqIBM5tAfALcd)F&m@ zVVI!ljD{GSZ9>YAnk?L8`GHxsM`1d`+VL=`!_a5Ds5Yk%uL_Zjz-!<%t|t{3g@8<5 zEif7`#BXCPOXlI&2QECvjSO)@aiuL<+{OxXPC};Wa)V{?`3wnHr>6;QfJLd0t>a4D z!)+uUs2nvD^g!ZOqw;XCiWj!i`?~Yo$=7}u2xMDj0x}4NjkH-)(4cezlQ|~rb=y9C z^eFS6w$*ky0q+7#L$O6GL;hXkrvTCVnq|v+ts?Q;c}KH>xF$=1A)Xw?h19^xVy+7~ zoMs-@wzt@JU1lD4Cn~#hX)cV{9i_!%TkMbX%ne+mZ6@+m3OuwnJQX@_5#yqE$3uT9oNtLlGnj7yzZ>DZ<%gU7(&i#!jVa)UDAE7GF)#gUXzRFq&Fu2t7Gv>g6Na1mpoGA#Wh$cbkZDq2LrXP&bp zspB6LHVoxIdPE8LzHOtF%tg`Z>WWk7cv6GcYFTBOn_qdeT)BKPecQ){bO0mRMw413B2E!v zc(hC;sr4B&wYd!tQ~~4;nVQU!DvxpsKL7CpU`o8RGjqvdltZY;<_m0b(^8J2|d6V5MC$)x3jOk)Q6?Wro zo@Bx8X?A91bG#$M_;;CW+Gc(yb3C}z4mgio@8h0NhQ#7}ZQ&B>Fc;V{y%Wm9F!Pg! z#nS~_mo~;C2kye&76^a}%jaMEKpp(%RUS|{xpKYk2n&&7k!~^8OSoBgvFO&pL9H&= z!6k421{13h1}#hn^$H^ygA6aDO}REqnyHopKlq>dfe21XoR-1>Wr%*4aYR!Er{b#U z3%9@-X6h$3W}Gd@ZRYEi2ry~r&^9FWn|pO$KrF0yqw=G6ER%}B23Z{AC`GiDS0hx? zUYNLL)ot!;R&UGmtU}8&5O%;y0V%Ursj3NCYpNlIZWTy%<-UwOnlNy)PWvs0WVUhT z_v??K2g_War<++9C@*HLWWov|6^7s>{Zz2as8p=HUQgzQu#U~bl8#YPG;rW7l_~UO zzBZuJ0p);9G=csJv#ONX7RT7SRQSwWryJEE5wEF?T8PZQMgMH4*jM}47e029`YbiL zX@B4+ZVo!kywVt+lL@TtQ3AHyp%uA`A_mTN z{1=a;>pBN79)eSp8D#{xszeDR$I*k5G7efpaSsYp3#2{;#IHM?uM&n|I0p|3OiJ~L zfB`m%77YE=dTW4>ZICy$iSrnDi#B`*4po5v_OO>`a+q(psT*nrAMY zBUA4Co$|{YY|Tw>sQ8`%w&B=UE?>wTk!JME*DhhDJwou^%3v5F^NnwOg{Zqr2sOJ6 zVxu(~DKp7jM_eqpKw`$DWs1;s1VmmK2uK+?aW%L2lhoxRj$q_dVi0bwR<~Uux=~Hs z;aQN*YJL3I96<^m&|RQ5S5_U>CAvNBC*I@miz2TbM#!4ckH-thhY{(X5<;f5&w_HrRj}^o8c^R4j ziDsC9o@QZ{`dj8{zi1br%V*q9 z2=^c_AAvz&&ex11w_doONo^m8h%yJqcZpZ6ScS@zOf%#cTLm`^e3>HJZxmPZ7?F83 z64b)19LP|QMCO=i709Gzax%5-{UbwBK+sq>&hs#Mz{zqMLWDqc&MJ_qr9rcK4n>)s zf>R8OLu0LGt9MPCeVt~`MtAVc&KzYeMR|~4$Z)#2w4GatumEOtK1@7y@}JyvD1(M^ zi{s*MZ42XuSHf^p8^r%CNv?Zh9(+>ZxF0 z-V=H?utHpxp*xyxE@z&&qajji;Z3M%gRmTV*Xv|P0owMyff zgC8h_Mp#Ri02{{ZfGp(-b8*U@P8|bk7StI0v<(XsWJ^k>xrx~_!XorN#_ecl4gSX1 zM?fox_2O`XX1c3&^+E!{Q>QU1UH1Dx`7QCx{!@0ZSGSzeov8a&OU_h9214zb37==Q zjO9g^E9`7%g<(~&GN^%M{r2ns3eXo10V;advGKbw&RFD&_db^+8CTjO?^LL#J-lNa zKwcDV3U0=ztw}ASI{9Z=YGQWILWb~xT{yph=7gC~hjM^17Nm<~0{5MfGa`>k7DtCq zU>&*rb`ODrW(;wjIW@;~UoLNa={f?4c@-f1h{<77>A3Q_jnEh!p2HtblpgaKqnWg1 zRX&)ph5GWZMXq!l@m15M8YYAi~SqH#pQo4hjYW@zK^Fsn!Eg~91g~Av9)`1{`j|GBv z?%a<5*#|^sCs5T;GlUKx--I(?pC9?oZ{ZkMjv5xo{{L9JlV-b;B(d-J4ZwStXJjI? zvZ{I{yGa?flNQo~X8H<}%(Rnnp|8;&PDYv5q=`l~+3c<~}Q8e!S6%4HE@-QaU#M zX_mCWl~D!>gps@no%s$QbB0kpcZrnvDulde=32&DE?F0Rb+c{y;H`V#{hx2i+)wiN z-|Ai;^d8GL-Z08H3c&LrdY$u=K!0?Y%cv3dEUuh6$vQ{CzIUh2y$-enBmQ3XS4SO> zi)p81@C-U?594kW)esoG%iTIkINU0Spw_i0vmY9z>3>GvT#}!D^4TZ|qkf%P8!17` zhyWI*&X_vRg)F@LMG=gmLWjoT{cYR&fD1e`vg_U)$+KtA%GU@W-nXdJGrU2$>^JB1 zvH&BB*H%10*9IdZ*0*^n=_oI}qfK@TnScm19f6}?E`?_6FUqQ_=Ucn>uV<}isJ%>R zCTa%HU>uK3JU=6q;D<};ueBj7T)r&8;!Vpv-gW-f+R&Jb&Jh~QU_38A6%FS%u7DRt zCMD+B3GVe}RGcTg3$&_y8{Tr${fmF`FIwvH)#j_OzG=N+=~DQ|tyc^D+_%xQ;moXQ zB3#i95s1b54;5+dN0jL&_ww@m(|=x2&f(^}yf8m}-P~J9dsiEkf!1%E*Pg>5Q(pLT zMg^rAZ%g0H&{;0DnHP#b(I1W+;lgFO-_8^iyS?&wZ7f>VUMB)D492ybawmV*2&skW z;n#=p^8e@hNC|C=fPclA%VMlqi>HTBGI+;_j+qUYgNMPv=$tvVaMC)VqI42i0K;*J z&CeKmCyK&k`NR8nXQEql3=SOJkDw@3c`9y*A)J<54)X-kRD9IL<#F>x2M_Nj$Si6# ze6;$TMVx@HuKg_T8!en5$qmSJZlcza9(@-HypRuu* zmA{`+Vl&f2ZnSWG5v|XACgO%-(WylKXa{Q-7X|v_(8?dM)RiHU$nhs7rx`UQzM9i( zB?=(_2+rZJZF?BHxPgLk=f4XFPT`(=)@S!@eAe+8I0(@j7Ub3*sC$|9xZe&NN8yL^ z7tBHEdbe;{reGQDE1OHl%h)?KcHfWM3)bnJ@dIOJjESCuU+3hbuPc_m{0tm0%HwOU z>M@gA178*D{>``FXT06-B-Xnlc+ca@=g%9lbLCX0^6}usMJ_D3>Vs_wC_-qI+|U7J zu4*bD7_F)M_SvNhY-zdQpOsagr-Lo;wYSXJW zF{Xs{4ZnHWle<513?A@y|Hxz) zzJYI_Njy*0v2NgbjD7o1fk-$n%|(D}Hz92+c#N$Cism9F6R9(M87a4S%9}~W?g+Yf z&BRSZs)_J6$Do6W>e+AC1=hty3=1jYuIB*47?{2?bZ$L2W^j+_yUh}3hu2`$L~fF? z=KG$!^2cP_U`TqF0y^*X&gTVGh}L24TQF;K+l1)5Hr>1u0V%b6cW-TeXg)?L_^G_P zl(d0=ncIT3WsCfKF_=-JYcVqcUVFh3m%|aM5XGGQ z<8{`a;ExqLYXlJN(ezOCRJ=KdGKRYI${6KXDf9^*(%#EQHwRB&wgK#oR{4MWXbCkl zac^EbLOYr?f>=ggz+dE{fZO1(W@)dsiZVUREoSG2iH4f@;XWLL=VhaHJYhEw!5aGR zjpm^Kt(EDIKq2%hn2qPX1=Ks|3AL;r^p{4A?HrHS8~b95q>CF z_>_MP$|#{VP*poxrwd$~yR0|I`2QH-^?+Ny3$l3NQhoVgd~k#Pzd4bj(na zexNYc5Z6d1kScr$O!t^$;^{wV*tDuv7z&FzljcUD+l^tTVGB@-0(e0n+`I3&=8NDi z`4%}E=lzI@Ej)vukTl9s+UjuPB_*ZP5pMEvKiJ;g4i6`Fj>n>qVsK%yhS{)<+1BJH zL6x64f4hxFxeRA}a~!Sy09x)c!)4ZcPn8j_{9OWOD|7~?^$cv%P3I`#Z0MMfsq4g` z#|2eRTqP$g~{FD;BZ;{d6?$VhTOv+zY2*&UX1M~ks%^kDbU0fS+JLVXG zD~ONzK|vmme*XF9<|i%WEzqDtK{uzJ`*fZ)c-Fj;aO=~CG%VaWrIAMY6;+Qi=VAV5 zK7nZ6&hS*813p&FSZ}|D&D4(wvP@&37yw= z`>T3YH=G#cr+I#c%44l9# z!Q4+?&)55*b@b3LR{Hu$`FzlcpjNg%XZ}V+qcun(2F*3unSg-NSHU{)>MPng$SQx| zaJYg8Dyu$<-zgDZ0V8+5d38|i@^PmxrAdgdd8PNThR1c(gFdNY3pd~db5#u-V`O;P z#cgN)jXQ~Zi~-0n)UPNQI8zX~j7)ZAYX5i^ybUKGUeYSVQ)TQn5S3=(5{`FxSmjRJ ztCO*zJ?6ULW!ly=6))bmZBHYHa0#c%TfD%nncN%0E1D$G*ZX)wenWUhbGxD+wn+FF z4?f@g)t~*<=AZqOf8K)FP84V@Zl~&^7L_y1v0;OPuBCF{vBZy4dgc>!Wb4SzKYI*Cs^z!-5-eF z=^ciAUOQPZkJ`HExX{|$&F5V{dzDM5(Ny>r#YmC4Mqq65a1k9f5uoEI4}NE({5Xf! z3#gQ@zw>X41aRTA!Qr%3`=yKi!_b6u4}3msviyE;zu|dCMjnSl&;8aee1iQVZZ5~m z6BS2LI?e;zSd{&=#l_!z^Zn+*-ksXmMyigafB}hnbvj5wy*6?Z>EpS8OntmuV!N+(0LD7+{)_oHT<6 z$|2#E1$}nbZYs$lLUqd6;uP)YyeDl-sFOdGhqigAEViN<4q~oeuqG+XFOJe zza?+<4LDo|z{02B<3fYjk1lc)?w8_;{kmVWbz~fVCJ#m?fO#3d=rW(m^6ip-_pBTI z$U<0?sjUAQdZ(RxGmS)7%s&3%8gCWx5`>gdj9=wrZB(!cH0}>fj!85!93-G3de+u&rT}%8S(?3^`26mz(uHRYGhj3Cf+e z)tQ|4L5OM-FTFsArgAn9o3r|+4u9G@qy3mh$wqp%=%8#v#FV2Gu@-d{P>v8$7gzxM z2QGM5-hcL0MogvyeMoFI4~Dh`{b{+FXm>5^q>h)6Q7Z+x_oYZMt~@>A7i_1+Yx7Y zI*Mr~cSDMi(i$Z#aw>OuYHBw@)9=}8q%w94yldMa6%KYE^nmC-J6IN3Mr2l&Ub6(= zaqbtji?8c3@V7hy?b!+XmUF0a?!aI|(lG zAO_g4KMWo#3~xF!2uwT*jENHqTg~~_k4jPcc1y6+N|qi$X?@en+=Y8@;8kCb-s8ea zS-6i5+}+Dv6kpb+h1W45!ZR1UJ_-9l6bvIvk`?5b(V{#~t;Gf70xoSiYO8)r(R;3d zj0B^U1pikp9bsfX*t*;GZ#c3G#GRsiPZ_V(_4xZ2EkOzIZMg)_gElz5`smK)!L^5* zKl$Q|nOk#={o9!MO-jwi(ALIXBoFVjd}F`*7+mP}ZAV?avR7k<-QuR`RXT7pddEdw zS_{qRVZp4U>6lao6c1nU%RxHMO1lus_tZYbq}fAV^# za46G}*?2=847q_uoh}@T*Qrc^^(6i<$RMAVj9PsGugf&DAXtAiszJZ~*YlB8<;_@I znr#YHsQN0PvKNphoFi1`TJM0a5J^IW-ohc%Hzu@}LBr~K)41uRl{wa)k~N@o^XY?S#aB3&8A5FvHjiIIjb- zXzw-`aIL7K^A^Pxt2~g5wK|xFhXiPrtPur;e6@}>kc5-P)YZv~-2t`xmgtYb9(eO+ zaM0Zj{~iuX5O-ju01+PU5qo{_s`$sg$I7alvlfcNg%75g$;#@tA!DBU@DZcv@Zo~% z;2WniUSz=@)xQ1PZE@08O?3i$S($gU(=Ry6Rl^e=!HKT$zN=?A1v6?-?{s2&u!W}5 zp%ZKk#n{zzpNty?X9T3fm`~)M;1a?!a5h(Etb(^+%IsGCb4?xVR)?C;z#CM(6UJ;J z_sI|Kdsm0o`3VCdyibczvli{vZKDS~7!Q?cr+8E}olL{F*P<7G)_wxJt8}w|Bpy0% zPLE(SGO~D4nG}O^j64?))FSu-Z4H^Q>6Do5r!E!Z{NTauIj4$icozvZ=M3p1{gc&t zF8P!X80D&$D@h;al4FEXPU8*=w?CwWJmZFk^J_(=-e?5C^~aThug|QmS3X{%1h#}2 zBP@s+FSfX%Y#r-j&9PSQNqBmf%n%XxroKWR zUTeg8r4g5TXAq=Ko15Efq43kHAzQQiGtA*u-7_7cE&b*rBDaPJ-OFxdej<3H>|~WG z0vFkKqiDi=DW%IVIyt&DT#Y+LK|ZTz_C5@LhP9Cu<7vLT4_yfd&g*qmT^9($pYL!z zPpWH_Qn2acIVc6O{*pyF8;f#`TuA zA8SeF)iaG5ga@yB%SeN}b{%h}P=i6hSy{lIk0V$YQx!WXu&?GGM&m z0nnhldLdNjD%(sBzJ1#nFcU>nQpvM=!f{Ba1c$u_p7m#02$Oj@r}ve!@ZaAU8PO2e zDU9m!A%qbWvn;|cCJN%IVFfgNP|Z(n;RQb6lwjG5rf^4zx@O`yD7aWHN+jcrGEdON zP&Al+hz|e$%iq>N{PcpA2&+bN-EPg}zx6uF=o;d3UMA9u6|#dmz=^TFL|7PPQubRZa%0PS6;3_j%KU<8MsqvL2FnPp?u~HZjSJ7*sP#ek!4V6C+wwl?AUJKYxv9Bd?Yn-X zkmz9iws|u&;eI+yk&13x5oYzv+K4U$J~tg>(ZP|2hXpIt0*VbzEOcd68^Ni^{1e{c zJ$Y;W6`8{gmCVp)@Ds4;GWT^DiYb69X7vM7d2k$>O&vRi9w(hPQlDKE1TDmKga7CT z2X@YQJ<~W8LWE#jcq}8g*+g8`Nhi!+zS0i8qnqfowPOJVyY79D60Ry86Jt^=K4`pCu9UvDJR&w( z<6H?Lc}7e#?}JZjpt9s$jWw!Rd=a?^TjogCr+4L72Gr@47H58+!gNB#)Hkz?|#1d*(YDL!^wjp zFf-0e_c|HF8Tm4Vyo!z|WLE#+Vn(7p&!lZ0sdlTowob%f&vy6&bAa|q(UgAr2fEcr zw1dCFY31TMH0(AyCv%gn6b{-|!j#SEM!S)@-NU5_Lws*X2RlYwJ+^+1>(u&9t~=8z zL0WnkiVc3m6BrZ7kU;oGd{%>eO zj3zvnfHia$nS&|HJ4`n>lZ88>##S&!|Jgv!&IAbST7#iwBknocpyjLEhLud$RUX61K(*QkmTa_-R# zJL}w#C_ThDg4`Zi?}~JJEA%oYv_h|^7fn6fLj;KU{Mr3F!q_=mx!R0aBP9FYU859( zZNWO-PNI2@k(B4s*|`&@V<+ezxBK;rte9zoG~v8I!(0gG--j0*tqWe@Y%vW1BfST< z&w$UXxeZ?A>UkSZZ?_)hxCv>&K1M7{k+1ZG!PCO@fAh`Pn;Y$=ck9;O=7kbg1Ve(& z{(xb(G851VN&;3#VJuKU^MRWhxf_|xcMuujPMhNkZ6-{{nCOlYnvu{}31L=vos%uW zXdEA`nS;N&YpY6 za~=)Ca!*kJgb8Crv7;y&NrT0~Vub8O*!3H&;KjFfKFO0tD%uE~tn_%!J-!}6j7Ov% z{H@7p{2>jzvQW(>+-`0NT>7Ud(+Mz1=)l47cZLF?O#o=8kMyi!eGKfB@J^|iy!P91 zDBMsF+Fe8lJsEH{c_6=#ZUS^C69_YKy-mQp?A$HLKn6=6%pHSwMVk?<+uzBF6LVS_ zHp?{@eiB;FOENOoc052pat(>_Vx{9>!4`HX*pEqP8>zktQSC+WP&R$%y+RoUWU~Hh zb>Ne<-8+_wxc0UKQ!AaTbSOkM370 z$7kq}ip@=tP0NUi$G7iC8HEpoPYL~Ze}i%O6xV9ig@_T_VRe*7 z?+6e*cUdpiF|?*3Z7gEW=trmKGFyv8`yEqZaB~VQU5w3@ptH_aeJx$ zVa1zVUT&%-*aMM}2^qW58mjkmeuI4kdoBY^YisoP2TKutCFG)*Rn#e;AD*>_pmhYZ zjf-+dkSyT}p@frl6a<3EK}rUWhFRch>R#n4dxZMH2NFrwzqt&mUrO^D_OV1 z8r2D$tz;zfLBe#<$Vxa_6lygb#Plt=x!n!9!`~M>ive`Mq9FT}EQFCM%k&SK7f_Y1HTH z(fbQ;%xJD>YZQ28go(9p+JasKW3pn>m2>tDYXp!e8U+GoA9b(MwBUtgL9TnehJR<1 z-w-HRfD(|`2amx!p?1yM9Tt0VuTcKybzq)IK3^U06BB0Amx{yzhtL|le{UX@#aCJhlA^7jVCi$ z-{d`conp&lSAVH~3> zE5Mst-*@MqrdK#*3+)F-(GClvF&&O-gd5^fwwvYCA1ZORZXy9WKf=^9Q+=b7Fa!Buz4;GaJ^r@J&6If-G7%B zOd`U(G{Ttn^pY`qBOz=9)W7@ncfpm5<}zVmPApuozPI(TRL5`Hkeu=|-!+O@-74zu z2*kPH!n9uOo_z4V^1y*I5GOrRnK9f5yKU0{VqZF2bg82dGF&}Eb>Yrj1IiN=3GaR?Y?Z^s>7I^Ypx98xjb-PJ1CtPsbBaYLD}~RKF_NhPYjO)#7+^S z+xzt4;az2(RQ9b7=4;rt`LeB4FtpP+!BZ)S8{C-NZ-saD8~(RyqHpD*$I64heDMBp z^E~E2bOvx_ZcImN`lcqaN;|qFSKaH@fgBa$YK|i=-{yzMu$7e$PotEod*D)gil+pF z*VT6I=9X?wA)MlC0z#DFnowTv#~`SbG4K*7G2PU|oy}We2XG&Uui1<3&YipQ3U^sn zcU$0aa}#>a`i&A(2f;kg5V?ymn3=NxuoE1d^i=7>x|R zVW86EAtTF^BIxu{M&Pb2GzFXXEvvbvnh}^o)E- zg0>_w7*jg?$)JNiExX&?Ot>ExfqI@qr~CMwLsMtN{T97z!|SxZ6&_q&&yaRH^pk$LKu9 zLg~TlI{4rImw)*;Zdf2X$Y|~wg=o8lbs!%h0EuNrRMsfwTAhHR!3e?++bA;s;}b@>=6%`g~}yFj*3zd8Z;<5>0~kHtqZa{HMN;_5Ks3N>A|b<1e0 zj8%#^A77sDYC!t!2M(%ZMvXfLKv!YJr9ZAS7`{85HmHZj?(f{M(bu-!3u#k#96JAOx8iJ{ufKab?zq>i%rS-*y?34g0yeV8A5HvQ zEuXOT41Y;KF5~XiL?QWBo##H<0XOcE1Rt-(pWGM0J8cf8co`2&-%H@k+)bqs0{D2! z?XPsNid-}zvi8ShcSS@S?!~NrhtTzoVg(i6)sF}mN=5(P1-mR|NU^SK2Pb96edqmh z{j9z0jLI!&pMB0CrE3h8cs9-rHgK$VfOG01Pr?BUTTle|yE4XY7XFtuAjZ>*=wUJ=(Fsj{wU1B&lqvNY=lP182!%T{RnH6WWLDmF~_A<_M-2qbJZU~F#m9#sTLao2zJ=6 zWvl!(*VL#B%;9CcNYNPwCFDXB7g>!Mt9}UbV`tO&olxBg_EA6qi1}0u36MUBfspOmw7Gc!R*D< zPn&~sf+m467Wq_!Mt!n!MSeYRNc49FOjwU)@ z=KJ!8Ui~r}VDXCPx_Yfc4GWVUyqq$CT-34+FFX37-4%{oCw2RFb@p_O9=tk*;~(R? z-UQ2#uoCdAbovrnQaCy)fiPBJgf%kK@|~j6pN3Ck7#-C6&>AhuUwSPxw_z=eEqPX- z6*xgS+!%Mw>bvo09p93IX-j{W8*P;%4TZOikxC74Gy@xDNqDR<@XiJcZo79dwg@Zp zGz5$Mu4ykC2m6eAqL&eTEgv3|M*FqLg4iY4^!@VmP983(3Y|a^3J~T+rkyrVRp@SY zfG;>%7TY|w51L8-;2Y~Yj@pk7Fv@~wBSmaa{Z)vm9utCX{)58eQvl6>CSaMZA4KR$!uw)A21xymEn1*bxEm? z`CJO-!|J$1`G7wjKTfz`4R>$*9F=yDun)#-c__|>qBeRlZ;KvxbCcb=UIb$ZM1pZPWfDn6bXgGor=4_{`OL?>1bfjIVZo4 zK@jex!JiBPGQv?KjG$+EQJx3O@Nnf*zL{fcn)LAK8j!k0%jI6puuT95`nVk1@N`*V zfC9A6BeQ=PUFCl7Ea-WsvI?M$5zv}|-NHzKAjG>Ajs1(>#Y~qf^GZzYSXmqKndB8w z6>kpWhSA2t#65ss9mBoyL_!`#C>Wr=Is^G1{parHKKuX2@PHfa%iJ zF_AiDJZOlmEnES@HLpbc$Wp!eJL}}*YAoLnwW>CF0#1jhuTY@r4- zrGrhiVD1M8L4{}uft_F5UW1g71Hhcq^rH1UFAAw<-8sB%&!S?^z?f3M9@-v#&2)txU z?HSyH-!*+Ho)=hxzJ9YN33_SKcwE8Te2cG^a=;5|ti?OwWCVP5>?{(mzjydxVaT5p zRI)o558keY7e}0kbe$-t%Ax#bbUmJhc)q@AbOa{v@URPflmPgIZxd`cbHiyDWz6*l zFMsfeS(LffKPdA2v^J~aB6nK=p6&ij@XU{|DmH8LQlua7zs4dpAtIVzmftfl5gB` zT!ULh+-Q&j!bg`Y;|TpL`>_6Ym<-tmTez{#h|;05UsnI6_>TcL3&E2^XO@iQcD)== z-Y8(;i%&n>d~*NcoHh1M8_+%}03kJAK-CX(96UumJ2_OYHdbvku%BNlGUI^(0k1cW zpl)Ss1Jq^-M4HFd#k110;q&k#L$3WM)&j_9lz~jW<4=4OVs`JO_Yt?Q&>8szJSH8> zx9>^N7xtip&Km|_Z}HniS2S^ZtL<^ds%oQ59bxUJy>{)^8GM!{%`%HXm@a}uttngQ z4>y$_Ag<~pR#yk@E@Ib`Ihk=fdX(@CMC1Ffe9<{VF0E}zUTy$aK&ZbvP7KsLeq~2N z-0p~i@1EEIFvh5JhnZ>T&OK)XL8{DVoh&fSJ(lml1}^{AyY3P6gD1hXl#LF&@P|8q@6U?h%%#}kL5nl2w5ES)}ES^7G|(r2o`x4>3o zdGIV{#(0#5(#YT+fo(LyjqYqN>yap`anHu5+EtVLgqPA8fq>m-lwfHlk}r#X+%uKU zHFoO`1E@ZkkmLF%un6yL!Uoc<6SFsA3$2$6Gb61Cw}bp}2MN;CA^1Ix4WE7W`tWkc!2 z;laTrCR)T=0j>jzZhbU-cM;;dR@S8ITQJUh!1muI9e3Pb@aY5xZO3srGg_IFQ9gt| zhNOh<-np^)UAqat>-13jF5V79yo@n*FAW4iU=5k#{r4Z z4YbM;*6fAOH^Nf;`v|qS08O|?B8m{hPe`YwN)ul3 zmx66)4iD8{_PQH6pmg(uDRHK7$NH%H}KR$gEvO-$zR=AZDCfRB<5Ka%+j4bNwE6V(}0_<6~!>M1dvQ$@^BzTQupy6<=O zuSDJtgtcNdwgT1!p29+Szh}o(KIyDtrRWmt#)udA1Lrzf zl)%z~8*NM@b#O=_^jj^SP`cIXbZ6Y#UD>GQs8Q2izm)^~tVF`%Mang-4y>yyPXg7? zHIP-upufz1&$B-OGf)tc;(1TNRZQh8V_gWlO4>g7|L`@LF|GM#;USq+%zHqd0 zt^>4>zC_5=LZgi&FQI059q7?#Kby5Nj$OC@=F`tV z9o#sYd|Y$k2M?)vFokH9t$goYQ)6vmjdRP{5rHr@I-es)biT@%5k~Hp*F~Ov_2oA+ zFSOr8^l77dli?N-bNg`H$~*Hngbx~3pUL3C`M^}g@y+0-rr~jTe(y%8XrRq{Pob!T=FseMV z11F;c>-uGioszneOgK-Wp7ueHfPFC&QZ}QH+(oaVyeOk1gBQ&bU4P%#?62XXwu_iPrn3ZNU zT|lqN)#+Y?_?euoAtJr@Y;YO6DIZpqU1X2z6t=~=nlf^bnvQ$a_to4XQEU_fzcFCJ zr(_>OdDToT_2T!g-Lu`d1ahvttTlo>_sO%QmBUbGygOxK7eI`5;PHX?g^)DDevFS+tOfwg?G&S zK3&h%EdR=~@_$f^=Fas&k-JB~|6N9k=f|{Lr5D}pDxjU(V<9Rl)tug07TE}f-U&;! zRm)y9d{+4K`NL|J+VxiQbf=V9bJ?0DqmSzfR&3N8g?^aK9+gby7HrKgS6K`eSn zQ0;TY9mm|g)QRst_+$jt-~Ri5+u1oU+Xm&%Senwqn|icuO58rv$LdRi)4tYKqKp|| zO#lEu07*naR5fqVXed5>^Lj;LHPcb2B}n7*+Ok($otbm~*q&{l)FInZqkh5_Vhs|Z zOIa~&R;$RAMZf7sLBrKMov-v`1!`}+?Vj?Qeb!PI(w`Q$%|kH!799Gi7O6u!l5ahe z?z~8|jDW1}tL<`ce>r`a65^t=y+6JeF-HkeHaiy@T#fs=!nh507iGhIpb!Za9t@|N zx`u71z4hD5y9);wPZR73ruJlPT5zSCw96VMjJR;f5(>_xT{HjMJ9BRKL}Lu#0fMbz z%LKXDjr>w0j(%-!oTmW#$7~n*b}7%qr&mAAu+8Yn6LGeelD&Gk`Skjyn>*KUSAOlP zP9wy3hq;joFnD{>sjL}VZw}vVt{fK3ap}h9#bN7p;wn*?M~(0aW^)^i=_{@OIl_yL zpl+PEPUf9xxRg&L1o%%MR%Y#sK;trt^BB^i?`F;_n%nYdMPeqDqv0tA&l)?3kW>=k zZ#1$9+wbr}1~m}O@QuI719*$BMkROwo~$dnmizTpBa#!wN65dNx5Bn*lq$N}nD(oV zgZc8yf_dUC2He$L+BPGwCJ;a1!QrjI3SEOUJmlFZkl;lVA=mS%6OA#4b}3B8J3NC4 zzs$S7ml8^`c8~9ka6eQ;tFKODruYR``N;cw0bSH({GjBfz5k$c% zR4#!uD6L#>D(!#%@_GExc{|~5u0hcby7g#1@7X-|XMGR{oCpO^^|nQ*et5PMXuC$P z3H~WWwm*7NFn{RURmzg|P2M+gU&u1CP%* zygf@v{Dhx%u0F_ir{oWbHk^^X=v+>-Qo-JRKD+L&DUy!=a@NcVo2#suhZvBxROekh3kNl$di;(b z6C6hNF7$QJ&Eoxx&@C3;JUl+5pb_iFR- z;qA@s=2)yT!{hhv-wi)3;g_2`XLqI^LWi51piwV4Ok$(`x@vW4L_Tp_KX11Tt~h;% zfkddwXT)%HzjZC0#Cm%AI2aSD2~UUap}*3E_s$V7^`E8OOq4e_)m!Wl*9S`@qvpHb zcEF@VCijv%R}S(*qH#ghyo&q^B3TsjM{<~KD7diIuejA9k z`EZ;YA5_B(y{oJG&pN^N>`HF38yTAQ?=?r*NHmuwdWkSB(+KdhM*5Vb=*PqO=u(S$ zM6w+gA$OXRPDi#WX>P*sbao{gj+|(unp&|v&R)v@U8BQssSnSgY3;+y16DjhX!dSC z7{#YFY4lzh^)`|WpIm(vNifvE;^5$@b8aqImib7hLce_1;`%qwAhddnK+OR;mZPAK z+;-P;vkQx-7z7nK&V?dkiSCpJnvCnW%4TE(GJHHBM$O9IZK*{`8~whD? zH6sIr(gJS{(QO*ZodjD`J+I!zWx#m@PW%&fdvO;mH}K7AVQFYn@iRX)ww=-^m&W+ zPBy>!)o(Yq3y!$+`J;ue>0H`TU477&JW@6n+Pb#9SsjiUue&4z9V%t- zxY}#fnqZ*U_V5r+jkpL- zqc+Pp2K?H{5Z#L(0&?b{sG8Y}?l9R=xj6+OZW!&LI-_#(18(s{vZWf$EzM}BLJ9p* zkUfL%y%Co3cb^<7OG-7IrG*ZRnEKdmYF)v_5a=hRe<>Mc!(oxCbJkOew~{J1nOnM} zB7DuiqqkF`@sf*6?d)E0c2u!dlsQLH zh>*2-XYuc(g|qtI$kXbWNa*@Y|HH{Zxy`erK{9vO$np`a6?~=PJc~E#4b!j$RYcj) zY?yREM2*`a1V+x8z&x(u711Yax(WwC2v&L6GZ`Ey`jPg_3cZr+%jD+x924@Cil{gl zN;(Lcv+HZfD4~Q1p`aOaLAVZ~g6-u_Lv3OHA}jDlR+4a4Bd)b~lycp#VdIZVNWO(A zF2heAbS6i_^{elT$q(^+MWs04iVMf6!1*&4&e~5jXvJ@y(HlWS-qEaeSh#`@_+bycQ556-(}h1aehaY@BtpUG~b2k2*!5} z_c18JCe;40_XMec5w4M$curA2&kFw4*KGj1cYkyBliSsm(g^1Vbu^t&haBr_I?F(_ zKtogQ1Wz4m7sTLq75AqQ;qZJG45#s(-HWd#h=1{Cf6?w2Z#Vzvzy9B6*XcW-eiDxn z_F=Aav?k7*Hbdu}4Yh6GqO`WIc_DL?S8`{tV=SYA}a6lCPJ|)X=`utJz zQ1K*p*GZOWUANHz*O5l(HcRPDvdB##kabh&e7Do35>a*W9E*^JEU%j#RS zUNFEFBXo?)+QaSgtP!9{Li0h=!wr7n)-j)Ta`Nlun_7wyOmI%wFIecFGP6SFkOi9()7tzCLGUI5C9;+kyHLgi6v}j}w}`_k6V{qk9)yH5d8i26XuCw#kma+TYb4C1Ld3a0Bv*IOhjKw+)nLLahJ zw4Hf4#v?_vlu-wF2CMaP=87n}X>-qJ=}Ds-M~`qhlI-I;t*_G!1}JvxwsW_S`McEy zZ7EI4$1(5*ErXNfg{V6paL-OG^)d=h`%R0$Bg20XGb4_G52h*XT`}@&q#!D$Mvq{G zY}RcBO3S!{5QP%OX>tYY{uVoRqg$3|DT;}ti%>f0M5|S~ZDX9hesK6nOx~n;0;EC~ zaQV9lWo1Ju#@NkM^>E5Hj8xBp!BcfDCgN)0V+9j<1EaT*h(gNmz7~|FOndJoA@(K( zs`EU|o$>V9o1)}8dhs~RK|QsLaFdSf@St!_+tI&j9mS10DGLQG+dtFzoq$=-y#wD$ z!o8uxc(=|)sihH-t5AEm6Dj`p<;mW)l+RSO9t@7=O$0`S?c)!=Lg{L|j#Gk3LIG^k zvK~Dh20_l4Qgc|tV0y_V*S~AmW6cOZ{6L`9(M|H zS%|fzx@OK0ZKLM`(*08W%Emb-B+dX;{X?$=M4j+)J&nzt>!6dESYR z67XPG{Q4^RDoDNhslXc_{V))wUL#&-ht0%#X$2^8*M0Zxcbm_D_IXOpPA7|Y;AD)j z!tdO_HTe9hbk=pjAA@rYfs$Ki^gIQ$f8KdL$E`y97z*9M~dg@02{l$YqchTcW9H3o~uW7woHjSQ|vzmq2~ zH!t2k+w3=`aGYUc!k+=KCu*;D?lrnP4Ng1IpXAErnX!l7tz3pdQU4)?DX4yS@1v*N z9w^IZWMnOyfFN%qLwW-92I0PG^La@(uA&O(Mca*rRzKqX?aLTx>C3VkiMrM=TF! zBv@F6BLsUVziUQXRlk|(-tK4zCq`wR zN?%?~Ls(Wx!YLMs(Jbb)L1G(GPZ?vqY}+sjDBLUsE?fD)F`&8+*6JnbXOsZC;KC@B z0esC+9tA(TKKwlmTW@>3tc;Hm557E6-)ct*x7oBONW9#pbKif=kYZ9lT3TPFE6l`c z9eymc(1HWFh@^R%#eKPrSB2j`>JYYDxrf%-DKVY)#8(H=bX*kCcMvf!DLEW;Kik;% z#&yVbTgMsZwRj|je;AM1Md9|%dz(9-zTG_f#h-1y{MFxYzWVi-v#S59?SvX-<0Z;Q zV>D$U9S!5{U}5ROIX}Kdp2tn-bC2M^*(sw;a3C_t_A=%!UJ~}t9R$~I16ZVv~O%hiPD8E@KIyDj?Vp8oEK?`K3o2CT68>d7j5 zWc*3n_*~rF+-uZ)?>IUh-yJzK3Z{9cH+e8F!tv!!xiz}Dc(GjdN7uKCG#JhO=;H_Z z#4v9Wcjp{C*s#I6l}qC4f#pOjgO1G2-h zk1yOmH`tZ*&k%7F)WV82U)btJ93Y;?W{CbcQ(tr9j!d^czY@#9gcgLFRd$tYHA*UG>OX+lSb2b&W z1bq#O<0?skFjMNT60dFaBW~r+r%pKj?T9Oy$1}cp;o4{UxD`RT5hDHq)^7r14vDJq zCU(`pl2DIt7lQh&OrgXsL&_0KETWL?{fx>~1YuwtU~>UqK!iqj!j&FTQt2e}pY(KY3L z^yDA^u}eQyZj&nCr&dl|cE7i;YhxXEdP9_`GrWiaj}zM0+v95X7A*G+zrzIu@FFYg zKm6)936NYuO@JO}={BQV=WQfao1|qt40A?X)S5-6?guwJd@N=)@os06tV9gDM#2jHIb# z@eV<_jFANufw&tH33z$?_EnZ;3M}3~O)+s5TZk&a=cH|hjNtCxe=xrZ4?8@Vu(k)F zk+yal6=1jFt6IO`JRU_!!I@uj5B`g-;F=MAEoOA-(_pmNluPbP>;7g=lqH=Ka7r)u zMbX*l^x|1-R#GHyUpE4HQ~u_5th>41E(4!j{e1K2b|b3OLZsidCg!Bo_ZN+Z-r5Yb z`f9*_F1Cy6tBJKCw_{Oi7QPR)F2@sFg~AvTPH%pRYME0{Yfqi9=ag`!N-`pLn?6MW zfqTvgiXaz_toKKOMW5OU2ZIxWr2GAh4#yqLHSf zUixuZgPPJ*O8I9#U)i;Nx9ot7MoXh^K_@me#Y5(_mGG{)x;N(?3$F?V;Tuu7#*=T5$H+0XTCS6*>aG7mzkt`d;NxKFSN30Wuv{nh-Twv^oiN_39`T zj(ZA@h{ACC&icJ#wcDb3Nob zXs+N^kyEc5rdxw?5X0}~haX{C8l9EJVeJLML0HdRTBQu*Y!SW6-of_)$nS6A3$XZ~ za9E?SaV5P^^YP7;rv2S~RPskZKF;%x|0?5@2d`l)*a^W4niS8M4n5Xr9WKI9`PQ@M>j;6A1((TpFCS09z-OO+ zI_ZrFr0q{w)r#t<%yF~!jC&2s%qhbORz|4wksfrxZhcP+SepxY+`PiWT-*^h7t^xx zHG>6hPqR<&Jxbv`%_Y?~HzC)_u~%D9cC~dZSBif9?D}V&#q)4;_%?hr-{YTA#q1nV zeMZRKZ)fq*QJ;tr1Q~ze5AL&+)4M|0d)%T@N+m_pCk!tI)~E#n?UHcNXovb6JW*~# zmvEXwSuQ4qUTrkOAYZCaKFY`bRO6W-<)h8;W@+JWuF@9<(%C|Vvva$(RN?fScB%-z zS>o}wWgaJvN{F{Y&{4{|NQ*o`1!Yi0;VWrffzhEdXUT)nR{bjJz5P^MwDT#!w5wdD z2GinA6pHz<%Uq=jALT*BXWm{K5p3mxlr8NY$n1qW@p6Pk3bhm`W>vO7jeKnPi~jkh-5#E& zMa;_RWL!ZZXZ8uL^nV z;ZOeR8|%W1>e>DNy=s1Z@kj39dafx1OjF|e?wPkMO|ZlZ1Smx`(KhA9@H#9=pqdc2 zZTy$*IPogC%B4U5LciYx+!KoL{#_sGLHyPPiuIM*P zC^}qD$vAB9(Jy|Mulmn7|K{KPyUn-1`rYQz%`2OSjjV4q5;J+blu*SH=>7NQTbTq4 z!6!)O)~y@OQNEci^=H1P_T!hhvAof|w(;wK*QTaVpWdru26rzA5kB@1)IaI6cEgJk ze3d_o0_&*!?kfU|aIY;}oG(6EuFe4}8jL5R_K(Xt3BrmsTD#i9&a-y%uue!{L#~-T zPB1#3=ka&nk9+Y!3pY!U;A`ZR1&hy(TqX|$gkF8yhM!zA+(qf)iJDsTJ|(ElTw+I8 zJ5C_W`EiSv@3d2e>?Z|p5IhI)`>H;ad+dweUEO=SIe67}OTm7;cWd*D`+wOeXhp8w zywqG!BOAdS=6PCV)95P!p1)3iAKnS(^W=`BHcm_Tt~9J_bCz=;UP|jc1JdaApt6i+ zCYmuL1&+|l9Ffscm@i-Lt509b{iZ={{>{_@H);(De_W>IgX1w~1cL6Qw$h@d4u(df zEP5IMvpe=>^E=_~ES@?2u0^nEozEXWO6jB=o7*|X7pa|-6wqGLod+FCbd>DdFV70X zsr}Uv(tA${)r(SEqm24J3TeLe7ClTKDZLNoC5RAm_-MT$OGgCtr-9?}M}zlK(qzk$ ztxLYmd1&Db*N*X+3=^7fec)MePTFdK6Qf}fac|;-9WRZ($RL6L+2=8w&dw!Ucm`CZ z1mh@18+?FDjgijMXuV279jgMm?i+BGR(bSSDN&RWcgBL@tT@ zOhYP9nKNlt#cP4zt`n9nATftg#SE9FFY^+9+!G4iju0x7LUZlfIt9#=dFsu;W>J?& zy%8h}_(5RBPv@rnwI6H?IT*R@^=uQ082yvNf1khpYV$+KPE7O%O>ZB0<@IOa?0bbK zhRb+oE(o2g#{H2C{1{+imM|yuvP^W4_XT^De;-!xu(B7V3-{b=w)Qt~ zaU=|D!0S)+H;GA&>+qDtZ@>I5bl%(C`24}li3|?I?@}-Ljsk*#@Ia!zZ)>;Q7_J0N zX7RuwbeL=9)LItvGzsJDojdgBfBl!6$4|fCoczP9&2r1NQ$Sk^!D)ZOr!V!O9Ujkq zj+du%mxQ%{>-M!2P#v%cE^|RTJz0bl1E0PT?_DJL%)fm7^>@t+*`PEYssh4pf_ao* z|8YMp0)uB2#3J9(SE5hV7YJalN%l1q#*XKV3@GI} zV<;n6al28Ce)YnEm7#82iMiL|_HA>06}x0b1*4DW0+5D&5Dgoi^$$~wY^p7%Mfci; zVHEL=qS1~Ei$?cnxu#lUR50JD!x`1a6XrzsT1#~v@6LKJ8Y9^EqIs;{Ags1Uq>Iv? z_sqF#6OaIc>PKr7nzq6-i*$gD_rP9*{RHRC?~!rf_0Uz@#>jv`wAFBr6{&P}^nBz{ zX{23i^%`kcmVpG>v^-^S)Cjd=W*(4RdiW8pl&37EuF94B{sYc=Y4ke@N(4D&B%tRL zGPn!~6mnvs!+JkMSD96TD1ffO=>+rCi}h|gl8#$}I{gAbXA>|`MO`|jjwck9BC@h~ zjif4r8ze+5Wd|`3#=Q}dfUtuDjDX)ZHYkUIX7m+9`$xb*;B@4wwn|$E1otklbb(TK z3)g}r(@>P$@4k9G1fB51h_)=RYKwtpSlaiv<>uXj1vD;TPWkU)oyXfhy+y6{e-aPz zD~GUnf8ihn{p4D3_iFoYh+3Lm-9Je_KX++9diMv)UWMqy(H56=p@YuLdNwq_)+%ze zAGd)d;kwk*CPHD(?D_Ud%KRv0{z-7gZrmr+-ZEsRR^)up3~X^p1@)OmpuZcglRgvn z9Zz=H;AsMIHvW%Jw+lV~;^r@-)8B8Ny!dAGn=cC$Z`J?9Pe0G4Reg2nDQ3!yK9#6~ z;q$pIU?A7Zjdpzax;Ygmb(#>bVFSwITR$l-qZ~UCoV1nCx3#PFQ!L*EY~3+j6?$D> z3g@f}c70o!$rjg7f>$F1;mX1P0I?XSx_j0|dA>^t$a#|A^^c1T;0hc%1zGRoJq$ncDAQRT3aWIIs6(>Ok41!I_914^$uN(=#7x@ zk@WietZ%Ch{mS5i(Y}HjqRlFCz}x}4!`Zy59>3K`+}8T{Sq89m2$W%K&qbT4w2EdS zTA76YDZtRz3vQ`ddl1D5Mb^{|(*U|vFuJ{l&j={t;aWfy?${*v?T%13k{H1zlrRMd z)qr&E6qY=z+87P8aY68VRyUY3rCDyc5TAd)1k>^7?tMFm3y8+ds{>9OV>(Jj87%e{ zzS|^fR+;nRwUt#dJNxE-5dVHr$0cZ9wfi)|b?7)~?X3(S_k*kIo8Qx<{>=A+Pe*{e zomyV>!+e(LG z*Eh!X9bTlhADUeUghf|)@Tq&j#tK!AdS-&23nyM*i$Ak`Yb6@Is*Eqc`FfP(osPqR zPa`SxZ4hz*Ez1DQFfIvo7PrG&2C_mQZ4-WWh3C{O~${yS{W&`OYh24 zV8Ny4LH6I6A1SbhXYy^{l-y>A6LOs4R-gh}1;HrM5WhJuqOaon1b+hCXQCkk^le6| z-Xnks+@b?5%-t_E`%(&Ily!`QMsNrDo<-QwN88Hx4^H9jG`F5LRTi#Z%EKcd3PH&o z@&l4>fy8(Sq%MqC-YWM*pCUCpj(Pi*DjrUTkR{jJwZnEs+GU>bum!d6PM>csocCP- z!+x78Ub>>9lwBA-t*%;MF~LjFP(FPbf!q4(BA$qd8By_j&jzMoU=$4QltW=A1IM*D z%-KDIBHkL$OyA%i1nTG8&+ziJLxtPN-K@S)-tx?AfAqu3v}pNdG7i6ZY;I|cyY9K@ z3?e8Y%8S9zV1>(hHuaY9k6h!9TW*k2j6wngtrm(ysB19_cmjx41;$ozdapvOlL^Wp zRvFglM@Lx_j6%U|!8PCVDbIqcn^pFt(@YJ$H8`$Xh@Wy+nF}o%D5qzGq3%7?u?ha@ zGt9R|WWV``7YJYu1~4MNoTG%mp>z1wffr%;l6Cg$MFd$#;`ncod9$LJ&%Xi|Yb=E} zA-EA?%Bd7>Q`FRk%eQq*&An3px)wa{m-YMOn{9$=v(BkJ*TBDRua`St|F|iumr}%h za1M^a*`)vdvOU=rTiPl9$3Nv6dj9137#ayaiVw{U&x>iAZxLxmw|dmJpXSc&ID{6r z9XIcCwaNdReG3vf%b?MPgSNCR`(T+&Xi=s9>k!c*Ema!ZaWXuvr{M^12;MoWvo|`p1I6_8OWunJ!Bvhi|z3D6A#{x-5Jul00 zDR%f=28ez}Io1zFWyU{T<1Ah~%OAElbIniS+iiXG9Zg1nfTyiUJl z)%SAmd4@wFx_DLA%AR$5VC^@-Mu@Q$r|(YZiKY?bz;j0bvlQsJ863fTkZbI60{2R5 zfA(HAN`4tyU*_$|w{)0HxYYZGmMNI%jb?#tZ7DQaV}izvfs5R#v>lMR&3w>>l9AZ` z%)2JcM^WgO0Sw;{y+iXsXSa_{^X4Dfc zh7ps4%N+;%wIN(V6M02eICu{<7vtVryt8=5+)VvN`@vgVeAfMX2CUt0xUHbA5~>_& z`{*Y|hdX0QU-z4`=a$ybDXuZJGHm2q?2ovL+}2(BWTk3$*WkP#=$#U(gLgNYD@2UD zK;uRj#P|v;_k0NP`7P@ozPw?fO=sNY)x!0^w-KXyd~2wEs5UqDCbaZTD}EvGauFx; zg9Z2lsTPp@A6?)AtB0$RloJ@$013m{%9v~Y7Wa=mb{&4|shrsnTrLcw<7b8JH)Oxt zYVP~@Uu?eow&TgOsE)4}eWZ(=!wYad-2q){kK+Wa7kM52pB0k){Mpr% zp%GntP+21+>YU2g!Qlk1CJm?8u@p!SQ@*>$tH9 z=5R-1RLrEqOXZs9aBAM}O3{7rJ;rnitwUT(4W`-KywM$l_lcVGJvzv*(u1q^kww7OWqJli-{rHh zu=ZQKV-LEeAZl4Mi$XN|AqN>sl(#wh>6hVS$!;+1?sq*HZ&$|T)kdQ%ytEV+e4&d# z8l!azXimm1-Atk2*YX=h<1gP(rk&=l;D$GeA}d+N>)YE)Te~G4(DM-Be8V0Q#$&x{ zP(Vys5I+r6$O0B=f4t;fm3pSo5qK+ec{Qri{SH8vvRPTvnCgUJjJNhF!c6OX#7C7fYhxyq#u0` zP8KT0t>U0DTesWz^8VfXbu_2Jt~s_flBo2-`L@0fN}GD%smuLhm|X(tyWiHed%F8x zw51Fip(IpvY)qYrKbE+TI~HVg*P))b@!{9s|1j%K9u@>}<7(?l+JgU#t0bj>PM5SD z5L=k0BM+Y7nRRFT{lnH|*!JeAN%A^HX8XI`SVv8UAKtjL`Rq^rtRMxuT{I!z2<*#t z6Mj^uxA7(3jLS!e3?8H3P6?S8vHN$zf{T4r&wU*WwW7W_+xq7ip2ykI*j#OYjxP&C>AV!PsgrPv+&JbfDNAEW_=SJ zD~bu8!00zuFqf#L`jb5mt-CW?c-90zh58^q!Ryc3mEcwDj~Fp~MP}IvesGas*=xQ{ z8~1HM+>zGK&Jl2My@j*K&9d9o;M&=>&GqNG;Cg@54%5e-VI(-9puJISb&{}^o2+uI zpck+K*8O<$yhy!M{kl5I8uN>16efcu_@@D-)mGMaL{B(w1+MnayG0v{9e-0?c;iYt zbdUJ^~rugQWsT#%bV5u*`^li}&I4p6`^;M17V;M((cNzJtC;>22{YVB>9Y z95nZ67Zpng=IH7QwEfL2HqJ2Jw+~)!efZonrIEp6)Pp|Y@>vRJeRIvNb_XkZ){Zrb zf*W*)i+Ccw7)8WL+bSX6Bs{TjwbD;JvtwN>*f4Ww|>wf(mKrqwxf(R>SRXU2OED#9!Ge;Ei5A&G{5>W3BaXYxC1zNHF zR1Ex792B~zu=*YMDAW6RraI>3$|tQvbM>u&aX0S}1z(}V4^ZiZ-Mh16NY z-=vlF4_+(3G%VzYt!Dq`n~wZ_{ABaXpZ_9!9u6GZ%x65-4ut5`Ke@D9!+nEc)jLmD z$}Ont$4~zD4lPXtA0{{n1@zZBxWC5uQIt8pl=LeTrR_sT!0zuo45wcNU$ZHbw>;HP zaIVX5nFq4cS4<>}P-S7q$QO=2yS^Z3p$e zEJE*ho2#AbE2R5!z92&4BKO-AUv3lp_K3S&gq%IKt`(a9;<=GV^ow@}KY=w0wV&o+ zEMz2fzE7zh9-eHz_!%X%j!%FGJJNIKn&3A7z#=@!Ewhxy;tRM&t0}iOj1sCnYtANx zTE4?h?_^Q($rCKBb_NDqnR6v@%<~in5RTV|z-U511YoM5eZyL4N>D#~^x4c?aEm^D z-u$jzFmj=>ejWWFniM=X`P^%P@%~x+i=8!cdw1NyZud8L5ASYnS%1}tXTJ!-%WYeA zw4WQQh`9ZtKGaIppC2B z;aOkGnYkK#;J3P^^)I~5{*mZ1N~rCas?Uf<@YPuX3ONBr*%ucWjiPC%y*gdhju*?o ziI;-GR!3?-4_RdynZ~thJZKiiqUd+Qmp+<42d)|%e2b@+9IP)?|58F*g9prmjBY-- zWRDAbx0O+$dMA6e(uWK-0($b~Ne1rntT472TX1ER?mZks8b0O;K)@NL!Dn?(^|fUo z*6YFW`|okb)eR?sk%x{j4TAZ}6;TIRopn8#P{nOQAGGWJEry$BsJ&|t)wj+>Ss=RX zIupjwAfG{&y8K=xeDr)Fr-Fbc-K233uvM2|+vd#e%CkiPcuKk^D_bd_Wx{=C$jNH8 zHpn{*7Ddv$YxOfry_v(-0N6>Pu=RfOZHs)uz;GAV#=THaSrc?Inf7=yqk$m#0J<$) zzyE~^q@2$92l2b$M;{GgNxDoHt{si*3UP8_1AyB`MZDkPaW0%eRD+L zRL4cGx=&i@SdU8)4zA-H+=}-ZMR>v@qhgD={grrjjKJKNPXQndZfZ@>Jit&Og1KL7k@qil|j9%t#+ z*K)PBX}aor#(f;Ka{Ig^6V7jKZuUFB+UE85D-dVDv!3i2ePI!I zeJ0Z6noE(@x8DY{g_^i^=BmP{{_w6-L$z=ATGPg!%{r^_YP5jP^1}r~L9`-1y3&D@ z=N)uMc^(%GGRMx>Ry!n^Bby`W$0I_94Ryl-C0H1JZgpE2p`c6OnGgPi>H01lGh`V_ z)-0hj0ZZ}o+U({l<)?rI){L+vQy6=Frma=Z5VpDNUTcFc_B-WPpqKsdI=Q)x6&o?W z7#S053?3{^F&$w2*Qt6_tngqP97;$Z8wFI|IMy}ns6o}Ie~+Bqe$Obmd;L(3pI*DC zWX{N)0LO>;lTk8rT^To&&$Fk`Mro5vGjgjuX^b#;>w?G@_?-Nevx8^plgbVb+zqGe zE6KFIKOE~S#9P<}`3DUlRqzqm{Rr0WC9Q&{$kJiLp7eeQ=za>9fmQN8WA{jepndfm zft3aDanB)Q_mc;=ZnLiP)Ty@ZrNa3E`SPfD!89-4Q%L$(+GQxKu3GzJ{oM^} zf^+uss-A@(-{lSOcxLi#2?YB0*U)b<8%8uY#Hus@!#Z(>2$zo`^td1@OwfRAaQGoD z-k15|jXFP|*N?B%35)Q!r9%%0;we8IjvqRPWpVG6>8dz9P*y1n{N zw1msyuPqJ;rL5a`g&MzpeNks^3zuu!0A^kV!ZF+rN`>4T@t3v{68_k&^TE41DEh3) z-bI6*Ycm!a8k-}zT(sR`ZmicSiIW5--a`}0bzC>oj}iv)1)k)3)4v5$a0`9=&G$XO zTUhyL@tVGO*qW*$xEl4`IJ(!qZa3RZ^h$>nHgW(^K(D_la_!o|&5ljDxw+Yn2R8~l zxZV~!?Xs8K&GtjJQ^Yq zb9)9mem|>Ca4d2y;QHSfp#E_teR&->ZOMoTJ^Pq(0iAb{-+tZH5aQmv*$j;z1R9;NfC;$KiCoW7yoOA z|A1wMqcx{H0V4FAczn~DT@>NS7xT}D8< zzQ`?yvq4s1o0Y6>q+Ge?Q?lRzSBPp;hy$n8r`e$;oMA`+Ed}yNAjl0P(V3rj9qpHC zEe%%M0SReB3<9|7P1>RxES`|QGZgC!t=xMKTcl50~^0=Z`6*)9i~otzK=kO;Cj5T9!_rvc}n z1b$Rt+hWe(Ug_6$A>onA(;_E`W(Nj=x@9`9gQbDo%RqdVL23}a$!2G`^<#08;R@R; zCi`2WkXJ-3<;Nd?${LMGOJ$~NatX6!&z}m#rdXa-c>1cHVo8?qlX%GNL@e8ui4wxV z*dnw9{?uZdT)cErD|PBR9b^o7IG`;uDG47#czMDuZlWeE*qb8ZxT z@t1FoFiV}64K%02-aawUb}B&<9~ppvhN_IMwY9ZHTkG-RUCOa%;vkiBFFwFf`8F1r z>rxW@v(szLwyUzY%f?LFrDQE6#XU_eR^UiDPx=gm3{OU&#OZhn*DeHj$Xs$uK=z=4 zf9?rd5taCgb(WwC^JJ>TOnU~A&|UaOgNOL(Y~fs#@J5iNogR84k#_t%>Ulymi}TZM z>KT>0d+Z@P$3$7S%jXY%Qyvl5ZEvt&{`u^`5ZRvS2r!@x;5x<`VPi=;#yUrHfU+C3 zBf*2&KeU)*s-c4lKUx&rlp5kme>FP^2MP58LY)nnfKp-Ol9+G?NY)g}gamGA@K_!U zwWPC(rl@>?k6Hl}hcw_6>$N(xR5Lnb1(aPI)?+dIv}8EIPP!u_O8`=`C#WiQh?DiI z=A$g02fwL;$?jZI6H}X2FqHt*bBK5^PBMqxPZbj*aMyL*AqM5cJm_ZTw*%IJ7Kkez z#d>oA9fRpFh|2G2sG52$?;2vSRs|p^lXlZM#UJ73d;ar_dPpxFqmz7SC;hN)4>EL) z@+)oUMeSbu*K}sHU)*ON1Dnt$E8v;*N;;+>q!#SD;yEtaamz-#-{iOmw+l$8r6X$J zRe)mLXpgvTPcz?}`orY8_qzvf-@c>UrHnSeUyNu_1`I4pnNd>go_fFLIl{f2E*%lz;eiZxW{t^+^v+V7!xN>`u zPcxtrRL&B0gZff)!Ak!%R(^e;gi2Mo-r9VC@Up~H9c96tZYH`8=Jm|2p&5)!Y zriZuHNyJoNLWFej9nmg#-XC-92A--cl%sJ_KXVDKh9e*FjJr$J015X6dx&1XJc{|l ztpR%KWxYzg=2nKciHUG`2MK=g0U(~p=f1< zXjwrRA{f|T+en&N9fT*1bF2lli@Y+7j5)xGqYJPKRK*3y!Z~OfZq<0*17xe*qtXXJ z12i{S5u;=Z%HXf&DI-f*p5K+gcgi_yWj{ZCMU?n^Fp}M}OQW~YB0szH8yF2Iv%W>+ zzdoQ8*4GFox`D}Y0~6hl{XQP09VY{D77)-bC1E|}ga!3V45=$jg!bAm-NXZ1=dUee zJVE`yY=%Wapt(8Kj%o^bok7W;6u_8qc3$`ofOIHdm8)uYZl1J0=S@vt9h+zeaJj)Q z_)ajc_~xLsQaTj`rozWM-q8*F<^MYJ;)gUU!XnQ?i_pljKQc6naiARrUM5w=SISF+ zX`5q`m~`?D;^)j+C%R(8>=n*CGG!eUTuBC=Esq zVuFD|7Ec-*=am8DfyDaLmkqN)5?R+vET1J)>dvMz9w>Dzp&}I-Dls=8V&NFOcB2`<4AFvC50uv&?6T1ge=eTGIsnVzu&9+K7h%2T*afbl2 zBID05kF);>^`Hy@Bcwg~H*iaS`1n!6&iwT3r}FaW7tykf_^hkFl6XwH7E9S%#Ae&u zGh~&TIBSBmK}JYr4empLAT6MAOpmTdxWW6o?}=GQu&!^uc|;E-l;8nl8>T`(H6Q89 zs>6yEY36XuT+6FkOC7hipW;rYvGbGui6gFAZj#?JFCZ3f?uJ{kkBv}00H!OxF(zIL zb@DkkfX+2xv6j-sk>G+O623oqRwiHXaw6?U+3D|;{RwXETc4MsKOL24|NNBGg4veP zWrHu{qS?Nvh1Mm~1pwmNAjO!#H{@3gBmcIR_+g)e_?PYig7}RC=XUZm)&ACOJAz=dDXP7;VA! zv>#J?DZx8V?WfWakRV7Fw8{ZzM_vE`KmbWZK~x-fo~zlWzm&R%wK=>XB#d zPNLe6Km~f53@N>WF#MR`nI`;=iL7Z$lKH|h1Xsj6;TJ*DZu3S9iVW!O$#Hr9;zg`J z?yd4%D!0?jn3pmst!1%JIj6-t^2spM##B_x%M<6V0w`BgeNErA0jmH5*EGsjh#XZK zw}En52OI_?$7a%~?)yHz{Y|Ow1~*mk)b7;lc3}CLhDz84N|IEhOu0w{Sa)WdbAZ(|jCQ-IkRcEZ2Ii(`)^&Wt&#hj8b@oJ;aB!HC?iN z^vC!1M`_xWG6#R#yAXtC5~a74TgRXlQ`_OQwcp-T;qAg}?(6#&sr15YJ^pm<4HAO! zO)(WWkm|>JpMfVs5Z16L5>9`6)$s@BWJ>?+Cm;Lqr$2vJu5mH{!ebbKwT#XHmOTic zr-(9Q)e}mR1Tk76QOXX6xLu#H=jG)5RhbaTvLh_N?43I>&3IGj?a#9O+G0n zxKv-FH9h|kZQ$WPYecxSGnqX_cS;DB(S%cB85ael2uYReQNI&6y`b^@f>0_AcNMH0 zf98>K%wDkWvX9wzV~kl26?cV%?0iwE)09!m0aw5=2SG2o1{%RNrCOP*%uyVTK5jq2 zBaazTS{(^bnWQEh%AUcDY(p@O_cAT#F7y!?;zxiZf#2@s*@WrrfTNQ+=XagrUd`D) z{qAO&9zjgsz&uWL?WV0-0_-nL;q08K7z&NF$F?R+OSBR}0bJk|RcNKZ)O$^EQs)(9 zDQi6rcmj#aY$(I_iJJ-=GaE))g%>rbxlRbcO?yOsOXL+?nP(bMFmMMpx}f)H+gxWB z+sZiLT145EK9MYKO^74}=$7UP|MpVoCPUI?OzU0yn*P&9a5M9=vCw$psh12+0aNp% zLWyfy9*y8xMN##vhklw`ZFvEVG@Er{h$B26w~&+;ICRia=7|DNr8T5VLCIC$p$ePzs=T)i!cd&3^rxl>BP1^{6tQR|0FQ@l=)A?2u9 z8kz=WNUcXyqRy0Ih2FehZeHE~;hnF|%D1@#42pH4%jHEEwKOM*USASV(`bW^=MFIO zSY`JN?Qo`wu9;V?A35nFNrRO2L{9exD4A8j`<>3DEjHlYOk4x zPhV{*5=*rS8Kz|^v1#f^ooiVw@BL>DAeuD34+ClnZs%oQ(+u;H=RJ zqu_-TkwJ9fTtX{Tj9HVm`MjENYdKCDr-WnR6=FsCu4QQ(zjts5!6gh1Yc^9o)F3j3 zFj2~GbOUm!wQKr7%4KqU-pnz9DHp3J>^~uDF*quUb{Wqx5umqO+t@$YEyr(n%bW2r z=8)_1;-^=5!6Bi7V>1}VC2KC8gR_ehid!pP(-N*TDPKA&Q3j4S+J4Ir`~U~ZkRG2N zZulH$i(&te^`V{gP*?w)MMax5Pe!m~tYkt?OegfMH3D1^L1hA31{4rw(4<6rt1$31 z%Yl>GbsjzvgDW)Q8<<3nk+6Z3U$+s+1le+dBLS=U?91X1IZiX(C*Q`L@KTtTH;8aO zAneWsM-g1V#e0i0fLt5(bXfZ~XG}b5yvuq(&-iTgDqdU?WyVe1iSZEAl9m7?2ZKner%>A-)6syy2Y9pc1Ki*_;M@dyfjSQzH zAd$%UEyqh>J`)ANeA74{r{lE@8}sQ)Kzcd3+XJJb1u6Mx7v|E_EBhWuTmAQ80uc3g zmjDiY-aYy|?<_~cu(?SrtN<5D#v{Q)g#mD5GgZoplFaiFNG20HLuEZXhe+~HgkcWw zEvK(*1VIu26XL%H+x4c3Aok6H5XR=Qb0$v{))TMYr%Wc4u=A>GKy`BXdwneZUCU&g z?C{@lS)Ofj-1Ht(L-4m6GXJZD!=%zw>*TVYp+uBVMKpi|QSe>*Nq-e6CE{MT%5sj` zRQaF&^B>9=Pad*H^d+V! zK-zDAs6FN$1}JlcX1J?=)FZ4D#PZqmm*B@32ZgN=C>OSH!!@ZNASd5D|!){ynK zgYpkw{0_|r&FN>>#V%M|nsv(E`*$E6<8sO|_N((*+0j)S!Aj1ct9%#y>}uj0@QjcN z3IYmi5mb2}T%+wWEQKOzM8ysA03*Es-DD}zQXP{Cd4#%fbp1mO$WviOfXtcT0(iw( zUZL$6t8$74p)BBrRQGwU2;HNH9WHn39K0=BMN3d`hHqU?%D~ zrfNB2-;lBQVdQAXn)hB6cj;5gwv0OFnGaO&`k0%9Cyd9EI;2}3L%w7lxbd_W!(YT zntW(X`@}hJGsWvx7`1O+w$GG=`tkvf`A(yohP%R(2J*H}_?pSWEJK1|q2>l8{C!ub z5$$)qQsJ4wVsK?9pq?eY*y}3oM{Im~A z#H*BB+Ze({{t$TIb6Ku!5C%%}o|`0KFW6nL*|EcBphV2JY!F9eqXho3?*S%s06{z9 znCGK6On6O0q!TPRNS*e*ZF@8#ek%dm_Oze+B`ogS(57vNGJ$ws_fpjU*iPTofAv@U z*M3{4L@@Uayv^Bwx=mWYGZv%Kn#U1O=Vo9B}vUeY7Dqm~OEEjqA0< zZD2XzT3v$>o-9lgtW0fiO!VT5DaT8kcFQ4qF%%ArAmMp89f;N#v)kUm9z^#Z!DeUd zeK;@2Z}2LFJ{+#&j)c#mSj|OU#y>I4NQ9Uz~L8Cm%XNpPd60&-9dY{qhWk z@aFg&CUn6XBFqtj8#2H<`;dWSkm|gkRK|w?xpY!6l)pqpd^Nqq#56J?y}zccwdwjB zcWtx}9T4asM2YAFd~WcD(-Fk|KEyUCoLx#eefIc_%bm_9jvF2bh!BW(=a9ww9;Qig zc*)w_5Y2wVyy(Dm!hC3z@!}YJx2I>M4Q>DaIMhCJ(r- zkS5XPiG*6Bm^H+PNjN_wkoI}SI+j|{oN+WFfpHr(Szofp$as+An5WI2u^D-&0}G}& zz4ed>=oi&%&I|#hesEFENRiF@oi_sA5%jV>)J!J(BdzhhU1-d4xxGjd16mvGv?r6y`^JD&qvlp@(i-bs0sglkHys z^At!raih|cU}D7|inY3yhRYyqXa4z39#i;UvzoY7(=s}=TQA$QvvV|{x-nG-EpwKB znoiT(41qv1xdMfGY8jSY>rVOBMSFwujF$#wVJf{<`>*po5Tf1EUIoC0K)Og}!4exM zoIPsYN4=L1I2kO&*QTkAh zv(kM9w8&TMO}PwSMXovkN*H#@kL}Flr4Lr5reObMa@3UaY@aTxJ`)IPBlG~k5|50C z1A0^$UrGr|0E#&9B@IAK3ZpCc*m-`CurS>pUng${0cO?0&vx6GI94$EHBAJ*!WQIG zt#t#Ko@Bz)0gpz+7}UJ!%6s?q3B`I86` zmkI`_Oa_qIiMNRxa~Bhq@xz2^?8WrYano*WJT39Z@z6ZyQQy&enXv7|$n+FXs6&@f zCBhlsZe;Cr{)CJ5LD@NcSdLy8O#^(Oy@rC(Q5ve)l%qKkQcKLYlar$?ir?A)J<=wG zs&kGObGV!^h9l9h70m3uI(q7;$~$Jr-&^!LJsjVb2IFcwV`Nr)MtMT z$s!YV4;0M<|Q%6x)G#d^R36Q+cNf9*VStTKmqAf8y( z2ElSgf8Jd(ZyU_j#bAnk+^B}s^?Z1)zjj0Ca z17UG}CSFbktR3sA6m>ii5DMn zfuA>OGL8WR)pTZ;>C9Qb)7N_dL0_G{VH2=te-V<2+^#1sK$4-Z>5L^4m~r9Dbs@@F z;!^IM%l!8p{|p2g6@xk*AL)ykY)hCV?K3aU$-B@&;AA<@1=p1IkkvFNLrNI5glh+Ml{{+Ga|J zNl05ObFz<(mSZ>U5cPSPR(uktDTy4^L0XTuc>VefpSRE@jwpvANn)he(ljHwYbo-% z(bnhUreg*Dv2X1a<|F*c6MP2;tY0lFaB28J3a4(s71$ANrFxjS*lZ`1Y+K~F0U5A# z(p~_}+}mkkLRu!KUJ|BLatu)HxQV&!ewA*x2X}mxbp#s(lMp@vCY+Mrme(94#?xm_CQc3z z0gZV8lQQf-V-!ZB)UVs9@Jl|jiR8jkMw9jkJIeN-gXM9#x)w7OOkNvOnRrbr;;fBs zplF(RmvH`@F4CK$gV`%Ui#v&0h9He6WAov|X%}akd{BPE>T#)H;NThf&}MjxUv5WyLs zMWPR|uEzMxSsR%{m@n}J8>6vxM~6t#xRawT$^12UZ0+roU5=C3J=!T(1Uc2i&j{{a zCjUO~S0S(vG43TU5)YY+?XrCttiVSSOS}09AqjS*U5NXM+67Yl{d@bYBO=7Omk4}Y zLT%Klg^##gF%!nl{1J{hGY9yPfO>e%$Bn37t^sAkCd}dn5qXBDFvS7je0p6@(ClW; zLyClza#W9+K9Lo`uMz1sSYO+KIbLFZyx|JLdk5=dGEQ5qma5>~twItp{y{jWx9pXg6Ef;-mC8MPtPIM?i| zxuPNQTteyb4>~UxJ1tri<9-A4>9cmHTlDyd6qL}OX_aeVt+wP?m>{!}*843pwym^-HaNGPGc8SW4E;!8J815(JMMLhr!SUZ|C)a^ zijDyja5HP?4liS*aH?>lgM*rnaG{E{)f@9;%tfo^9rQ#^?}qs#)6y*0%A%=@wzPA| ze)ukJwO=VIH}#&h)ruv9uclJ>khLLrtk=HUzi3S`eM4)-49C3Gp+vlwnTi8KudOR4 zdSR9~lw$%e%gfdLwoN__ZFOPOk1n+i4(-34AR)RAlrxA-DTV|s!3vRWCXfL2xx~JG zZ>8;Eal=Ft0URtRCBw|*cF#~vlPccTV`eVjwVb_WPW8=S_}lb3lb!n<>A+-jvdaWk z5G^H4k)qWCRbgeManB`<2nge$bpJUS>hXgX(?#~BleR`x9cJl&&N!bYgj!~pTZ)O60-HJ#pe z>2GqH>jfI;>@AZWlN@6^#uaww4q<2xcgp$o8EM%M!ExQL-AvT(7)EhI^OxR@N`sD` z#M$P_Qe#4CfEE1YnIuZW)x}hHPGoJ5LVkm}Z*O-Tvs~iUNrWKAj+7TO2Z8vk7+^JVZbuRMIxExQ+)Lk~yZu z-+ghv?BbAc`t*6ZTbS@rGf@L^@6n9! zxCJ|J*{kIKAJ>vb;MYPXgofN3<1EDXj$kZh>E7SrosI(|XpIpxU^zlGu(j%-?krtm3Fu}cfvOlCBmgNPN7<@ITz`4QFiS(42e2p z-H~QuSuxg}(LB^P07qQy1%}xNw88iaYDun(-pH&d-%ofOWl5PUb5uyLcq5^Wg+-cT zBPb^nylIoLkmx9U>!E2>1eZaCe-sV!3y08W22L0B%yY^M9*{1~hf=Lu2-P^43M#ihtUI3yYaA0?JY+8bK{_L~S|Fu)FA+_nng-Q&*HR_q=JTT@XJw}SwX1EA zOa(9kL_1m=lt$7KiIvmzC{Zto(mY^c)!(uC)6D84 z?`F5!Zkf;a)^1F762;hYDN@sbQo9T~0}F6(SSQ%t8k9$m56bmZ;%|9sBd8^ck1 zr1pT+5Jp3Vmcbj#kzuQC%`j(q7~am#PL-ml&%XHyYFQAM5*%-GpFaS`e{~?=J@#%L zHt*h;mrqlSs(eaYD{{T~ny)PQ7yMh#!cu+g+mF{fSNhyI3W5wA}#%MqH_ zjB!GDCx>edXXU>w-;@y|^CsPq!l6;tg@?lAg0dHQL_#Hi)gFwZWlX7*_a9!;V7J5=oK%-=V=%@mIqj;{rP5p4OL z0z4M6jj1Kmtm`w>9eCQND!Ci31r%fw!hAtCO$>$@a!8agoCKn#C#!mx+Jk$$<<;vG z+=JC{4$e-gZ$=1h?<515643bAFCg%7(=;YZw_iZ!59 zw22|-9c@GCyTnhc=4k~j7?RWje5f#xMAoi5UUs%60^R_c5GGy9jaN4!+|&IB``{wx zJ*h}igGr!ChzQcfX99s@Gx~6eKy`}q!!gX~6=uXMgrD)w zeey{xz$?@Y_dLCYX{}&XePC@IHxRBI8cBS@ULnrMI-k9cr`-y8ZLtkuLa!0Jp({?v~dop3h`f~9KubvBNnLFWrJ&y(wN2W@Cevw2DZc8uAac|YSQ3iq#t z5kUit#OTE&jFXnpM)5s+#mwQH1rQOSVBQj7 zJq9z%@|@q6llE~R!JBVk zVsGml@xASHi3V8kgW>{1>sY@uvW+rhSu zkH1?;%QT$W%z7Tp3BMviyJk^R4jq6|ccSpZluYZQaBC)UUxYjTv)C#!S*!yCLlSFb zPMhfXhj;KkLP~dm)Iq0K+RGsFUNu%tA?r{O1!I88?A>=TP579f%PEWF_Wghe#oFX` zXO*Gr2_wQqqWZX#X^ZWtNF_|yE`b_!@R?~oc)ymkz0LR`?*BS`ZJP{-X+n`u{Rk~m{-t?jsp6{2YNXaLVS>c10MJgct8Y6*Uv`g)`>{b`Re=KTKthaX`IjLGP8 z@4>A$`S`0bS3}-yXC1^r*c4;ZNlapSM>h z{^`z>@;~4E1_lk@6Ny|6LM`yY!2=e>X&EMG_W?PAI^^hySlK{WQG+8s z<0Bpbn>xPrFF9JY5+Z?v3`ag*FBm0dYWDNJT8&|PV&1b%{<&`0l_~q1d1Sa7rE$x- zCT3t4L89tKq#a@=;%uZTYhz`LHf*`Z=t@e(L8oj7COalt#0I9!4We%=h>EW|2-$}b z0c{hBTP;S9Ltvos&NdmXhJbK;h`K@Rg&!H(j{b2~p%uH}(}d*R~cU*UKA9a>;XZE4*3 zgG;8PGs0V#Pz`|WxcMGg};<5y#VkGCLitWdVg(j-pCB#>gANZ3u~OY`m|S~Be9ST+d$hSfvSXu@@xPM z#7%br3PeES?|XNVo6&tZt}C?2Aad;Q*Zmd-Y}AVl3eTjV1pc>-O(|N{xn30*{)~-X za8OUyy42{ncda5GIApNDwoAri+l*`+Es#T}1jsoID6Yt~MQ;}o(JN*NT~q0Y9&=;b zwX2y3W;6k2?0{&c_SfkL3%81Mz zCV}>MiC;$D%DE~^Hhrec71el=N6mA7R_Ujv&Y+l**DaE?-+9u&Fy2UxC0E5Q^4FW@ zS%q<)2sfj^uL?Lyqb!O- zVBWqyE#LQ_mB$Yb%E3OTsa|qSHETcTM6Vub{pgh=$ju^s|~$9F*2fFltPSi=F+LI@mUqFNqKRk^w1*tU4pYo~+6b#A;jJ?3K|&PTwR=hL!?_pINXc@C>aGK?Ru% z?;|R4y^?3wI2Ne=ObPvee0){jUVz&W)hV8D3rvpP?ZdKh|0{M(;SV>(ReR^G>>Qkw z-Ot{Z+(H~-^aP(A^V1Q_cq*^mwA2xJQF2Z;?H~+Umd+@ zJ^WS+@^2kc=P)1IuJFZ-;5k3|2#0puO>18z<1VNx(>lkT{a7Ozc=`%4))m|J);2u| z0V87MWdgX@Pc#>@+13+Dt#jT*h`}+4>5E`T8-YyD%0VN)vca9@WNG+#J_@h31!Sr04Y;0vMEpGYr zM=ilf2p~wD3<8QwrvQkJteE`~ggcl8I}C2evPds%Ziqdp6NT%H?xBj4f^!i-%B=kM zOO4A*oXG_7A;}VFk2Dzv^2w}2my@>6W5+`QN|UBXkDOtBIXWV+FMEPcPmiHVI1E{C z@>pLTcbQym0#CT{BhyURxc9rJPAdAtxTW)z#yY>Ht-G2?=<~<+w{5ar&BZf?0^^R&nJ|KosmNwh07;+CE7Q?qC|WG@ z&SI8~%{gw*|BM5{-u7Pk=Ie*$7~ro6#yQ1n&IrBY&KRwpLsw~|C*U5lmy6ImPd+b) z+jq-PXgSYbU6%jn|Nei=cYpq4Il>OUi)m_N-Lz?}@I^VE(7J-?_aTC?CE6$(5;n9I z)qqx;JngcFg3KPKza+{Y4{#jNmI1_bM(CkG{I?$&>rx&)U}GqK(n&&~sP($@UK_sd z%LDdNT~2Q}N`a#}(CFNgbw&Ooy!d`*9YJUMk{Z=;KUHF<~_(A)`NykQpQ}3N;A$&ZKCetvYDrnM9@;kt>s?b>(RXvoA^Z_P) zMqrpje=Z{2L7c%)wE+|k7!Y%Z?+)~6=k9*?bDhu7R$-=E61Ip)F+m6%vTtt$gPM?d zI6^DwA5%B^amZNAm|yfkZ!SgQKJ#;cHgckXfWXbU_YN5j3cv&TA`jYRTPt2K>Gs3U$bzKLK!|D(l#EV`sGyU@)cctKQ! zGR883IbW?EPkICjw0c=JIH=P_)j}KwU>)m`a~gq}(NHXN-e?|lY~oSJSVYjKpK*`o zxd`jr^yA!@ZX5mon3!;{(SCkrC-~9pBj}ETwM+w6;JDle;d^pFg%qPwRCWFE@{i+W|u^PnyAb=Dyi!_K%P_qBI zAlMX6ttq6>#K~&`pJbH)N(7Y-rc5Z;4y@RQYF^Uj*hjYvvNq-_-vwA;kMXzEf;69v z$29_P7$5EQJdq$jWedD8G7zrSkn#?I`%XgYg1;)W9!?Sm$4!P<0aDvT&nQRHQy|ij z=4$&Tk#JyL-?5Ftpdx_N3aN5uqa5rm$}y&pYndhBQKFLAbcvL!YU?Ik%}HuNG$TyN zqAa_*X)B>{F!!kS!cP+{+3hRsKa(FS@6ae4owAILEuu85l9Ls23|E5ov_Zhfm?wium#F# zV++t|4mO)KGWdn(4P6ox@{EnFI1u!A?XM0qN}u2mIFJcWNgf|yy(1z%Kz$(`o$~Xu zH{~ay8JwO&#Pp6s5}zUAUov+tt{??(5rkfFOv48Ifgr9U%!u3WcPdj3`+HCxeEYld zIU3Q)XOGH@AAc+_@R0NK8t0Bfw5v@ta2A1aD?f&7!ZcjGudFtRqy!!d2QbjHQ6?nw zaV`l1X-Z6M07hs4srrmx^*wWk(U94+rnhWVWo}3~r@$3QdD1XfU_!EdO<8b&GGOmk zACut?TJBPFCS&17X(OeJD>t07d)fr=9b(d4vR}v$PnOY{lSfkJnL|vc5gx5>G>4}_ z4@^g`%-I>s52x2`Qb!Z&vu-qkrgr1 zMEv1R^Qq(8K2OD_246yt`ED7KtqMbyC^lDpM;aKP!^GqIF`?s zE;ZIeaMaZ>!)@uJ-Z!anF$fKdpRn7sHwwGt!@NNG-mM<$x>l(O(urz+oM zX;Scxc?2%ppjj<&XVN!d%8}R}j5uJ-b$;&-NAiC>GIUi24QT2fKyF{|Fc~~BA!07Jo zl{s425&NV56D@rC>^X=1ot4*TZ!u%yEyr5b~t&Up#@Hp=k;5AFK%auI(#=&%$@9@vMNtJ>%hs~fHGfp2}NC$wY3WjS! zY6Tk`z-F8EJ3=qHR<)2BFdmx14F;-9vD%SAL;IM>mO~hs8VS)NI*hfN$w~_hbD+14 zB?N|xvP=a^@UAQ29E2rDb0@Y9oEJ7=mT1E;qHE4jS`uvnhklsSIH7qq4dROs;1MDr zJmeC089;~-!iwAuf>ebk>INZ%icE+~c?V1}&)(oz(ZylKV;o#=Soxt0*UTj$l+q%S zz^4|{`Co9RM7}dwE!HP_oo^YCCVrKOna)ojp6=JDXQv6^d&*Jo=R}6NhAx}7=A|vn z$COQde)~_9uMP28bD6<*P`}UG=b?+{vc1gL&=&6fo${Cu;X(ZNO8Vw~T(o@{LIk4_ zsGCS05^Ra5n<{OrB78WU6{MWnh%g(ttsZqP!?6OHM@(T5m$oD3_X<&zfdF)2>7*8n z{;R*uUm1(-F+@Hin2u|TnE_Az-SFLp*oq={{VhygN~ zOBMume9-%9q{)Ro$hd`#kp;5(O#lmH2g%CpetVyvK4>q}BoV)PY#$|N^#elQGM_e2 zo4EaM%lRMlO|?#@rf0zgH?cY{b~f<>xe@+(K|+9C(jRwj|M8E1Lc_dUo;)GE z4+LaBKVe-*yEk}yMik&5kIKLNmp_-61S);4DT|3WAu7iRk#c-^$nghT<&tB@PjTnI z!gMPK(c?-y_CgLv`h>_p^tw(^nj-{np-6)?KY$$}JdU-*LT%bOVlp6wI`& zBgcn*PQJygLqxjZx8`NgJoCUQre(pkAV_AJqBXrey5y{%ZNd!zzXHQG-9%m@wOw-57=0tN1A&0(r{3Kqg0~qo3l>JB-IC;=2c)&oeF{3T|nlAZ`DRs&GS~wbSZbNLRy3wxoUHmR4NCPyPvT+=q^ho1|^^9gs{use z(E>?81VDVZi}|F0=+w0=C3TsQV3-MM&sog_ciWFYo35Wk~7e!f`T0$-dfhWRHGo0;>y_(75rHj5{prRE3 z6N$PXpvag)ILIe19djgu41Avm2tB;xX4u`&koGPv3^7v5(a(5@y?$P1Cq!AeU~SO; zVSB$~O>SpruWTJ0Ks#KMLl__eL?209eAeV-ytJ&%2_xE2i7ZgD57b|~k{=a6X>S}@ zOz%I^n6`d15B$x%LRKr+n3d=b&m?-lLfV8@r1K4A4FZd|DpB9&Xfro#wA|eTw+fQ$ zIi_k>4h#>|6}L1`>P&;~)9ay%b0FQ4JyHhtJYn(q&p%(5&nf@6#P}IuUL1qhUDi+@ z6HWZ`i_gm+{_s7H3LI}S-!Gj_8q4t$0}uKG(KhcP{ZDX*KZVe19tU5uQ=jff!*NX8 z56|j|R``T4(kXJpvrKIR7DRtAHEL4R)W%}`lCgKrikI4&>fRUfp{2M%^@@ICQ!9Nc zoWlY8Fsd##>#o`(j7Tpw;mArZbC!Hvj{Sg{s!eAMd7pTIn-DpKlSTg==%FzKU)&S| ztDa$W)Ut5lhr-63r$YoSWK0mAyEq^KyG=amw#K-(@G6ev0!J9(;IdX5 z7xckaUioP+?!l7|n~6bgoE3lpj7XSd?-AWqQ>=_yIFVaTj%=V$aMRMHXLZe~;;POD zbIootAQ-A)ou&v?=fq7k$g=C=np!=a&U6ap(rcFqq$%=GFMA@sT89^uBj2q1 zsq1JG#|pPfOh2mQuXymTY}-S9bjNnxUi`2g1r3>>0Wo!F7AYqQ8(-T{@wmMgJ3wT| zO+kmW=j`qI?z^YJ%yqtLdHTcmS4 zVXUw>XecllytXt8KVUQPqx*Lw@pteVd~@;&Gax22m?WT2Uo)QcF&Yo`RngKh7Iw^Y z84&kX|A7{u(OAbd3-eJ37!O?4aH(e<5Djt3++*1cb09hh8r+O|A_JPqa4@Y#V^R~v+EO>6JxBv46f*q z;F0o1KUul;UG8Xq(&X~h9>UXWjK+Jl;sr{T7jt7ls0gaT#`CS7%>8?YA-~)k^yry=<`Q-YSb49Bp7e$-c zTMM_NbkKKtZ=KPZxH{5^Ofn{;jKqdps6@LZ>=s(hYZ5m)trkK#35CPA1hS@)nA1@0 zq|G4Nw;*|%0WqLWwoSsE1zZxS6=Xi}hU5W+cL6BhHr?N0tT2v{3j1U$^50&n)n)lF z#87a@NdUw#EV~5x3<77rww27KJhYW$X}c2mlFtnvZMkDsJMSKBV~!*A1||d-xt9_f zYEoN@iZ0CHuzfTqy~9M19T-rzgGW;!3*iz>)No z`K#5*U@H-C^QO%FaLgJ|S_4)2+xL!D`=-s;e!t7#KJlB(&6W3N|KPF@BD3LYBxdGu zO;IV$2~#=~@MTor0l%Ev!dMu@Q~WWV zY-6syW)Ot4(Ez4Mi5F-`N@f!xg(w+bL+m{$&!Gs@q(nm!&8~^G?bzwb1aY z>46hzeb(Yy;Kpwup@7q)4$UR6-@rgHqm5{f>pqS*(-NADR1cNeEO=g(!?M@APy5ku zaGqdks66I`*SmxL@?T&4sr-LG|4X!yg!#Grv2f1brl z748U}?UU}x*?dZ09EZ3Q1H-J>005qZfL4m}p5 z;QbUc>J@EsUygO@3+CKW@KfPXQapeGx+XTYCig!YQb>(h=a)Vl7I1@Sm=*E?Ew^n@dIuhf_{+hraw#})kDH-}(zh4yoa)-&aMhWSmV#)zWx-TvOTeWT{AR1|B(&Ds!ry zfGQBFkJqRRNu!lRejBw+cV#6DCFs(7cNwu9SNw_|tFi4N_EUL!?n&V&&&dSQw(A-n@U0^y8vVN{(RiP~-vyJ{`Ese5d= zqpk-`?OPoaC#e0Z%;Ejst^aD@N8*41*B4xsKy!K|hGK4!WJ4hlvCx1#BVAG`->i*;&Na^g-gM~z@2 zBLcR@b)GlQu6XeYAMqkNf+m4)CT@BJ_R^0Lo?A-aM=+tCol)6_$c!<4Io}ZF&|=hp zI53gDJ_nt9a+dF)ZZ&liFAB}pmPIb>U56F*7Xl%=lDOe z5wnNO`2<+8y#nvA9-d{dE?<}b_{V4Ev#)N-lO5&@gnNZHAiLPVGcI?pcFMmzl7kLn7fh==>1Jp!2{S+@L+jLdU6>gCx*37XYJkAdzUV2q zK<(5t8$n;ol-od{TT`?kKdy6K^UQOZme5@pRotmzK+^ndz~;`$Cmf`K($mU_`0YFZ zwOfrP)(86H1aZDfN1P|YegV%-(lZ|_^C78plQOfe&p0H#^WU_V!+S5_S*2q=wa7&R z-K4b};v0gQA`AoW+eb1@gC+j_69Ke;E@2`@_w`cRZawM*j>JpJ-T|=D4xXltFeo!n zh8@pyB-iQ_?+dH4j+)kXeRKsNcBuJKpFseol9W_(z)lSuXjwOY1e>Q(~^+dB>E--$mq41stxJE;^cP?BO8SsFeZc^ zeY%#bi5Xk24p-AcNB=Kfq>(X)ahUvruKp5iewoqyr3ycOzg|biXT2G==YuxY5|~&_ z7|n8?TcW120fW#y=cOC!tYQ8eNQg1x0e8dD%fyZNF(z8{<_2pVj1}}uQJnFTa57#< z!+mg7$y#aDIB{blFY6jktOXJ?k>?!d#W<+}IS+EWC9u@i?qYN{Bsy_EXn(pS9#Ycn z#ltWv@N&jy#fHEx%)?_9E;r_w+}IbVV+!BfY?j>Va~#EDi?Bg#E4W4qhO)0DwA8KH z2gf%UPQM&*MEBt#8&eN9h%R!cZ0sGD)#knO8shYFbzEMY9kH*7y&y+V!J+TV$^57C z?~AQS|Ot~ESu3j$m>|MsP%vCL{Bj zc`uC$Edvhe1AXRkrYsDk>zWo!S#3UML*U%e+k-aukwqtr?H%yFoqj+706+jqL_t)* zqbiR7{1OIqUN&Hkn|BF4g=b$JI}(W%8l<@sf$a(tFnImkQ5B5YhYX0%1;v z1(8+wWKRw)m$u1(WG?=zrngFGHIJD?2s&>w$AG=%WRoi8C=6EGOxuM4Wo6Bqz8mSo z-_rDyZh6cj?|<#;%Mj`Up$w=>coJP3q2wtOQYuxQ&Oq~Art#^ERy9`;3Zx1XlPK~$ z#F6}ws+1rt3zb;H+=D>GO^|2pRT-J>^4Ytx+xG(4GL%N0RA8Y{N%~(Vs_)8wS5CbP z039SHX+HL$)+^f;$tc@Ffq^8_0&Q3Ammf}GNMocH8PQCyAdo~x#E7SD;)7jQD)3l{ z1=5>RTO1T1sy#O_&_%rh^`y%JBMi!J1$NZ!l{VJ9{QdBc2oU=&{m8#hf$gJAwT@3g z#xnkvtB%zta=cggdp}5Ae>>g@&kvDMs?%JSeQBh)mH`QO;OE##@O5eRd>9FjxI1An zeVfg!R|Hq(A@GJUfgd57jDs7WS*1f#lVB-Hi~C5NF#g^Zk{b6*#zdkb!2&y3f2iwL z?s^}w#*&@uzW@?@(e}R?uKbpu-ayb-xLHrxFXUmctJi6x?5v6HYnvC{Zlvb0VYDUQJXk zz=M>)4443s>bb@o5Qkwl*P!@nlW&;LRDuj_lyJM41XnOmnT;DpuUPNtvo@9WQP+r= zBiFsKtuQo(6x^0!s2ec`4z@}R0lu`# zZ*fY}N^ub)=Ln6Ox1@2dsVKN=ofzWjHi8N5-`pvOH}}f^@_?9nFd@cd0NfLBHj<5i zt8^x7fx$i6gqErtFD-S@me2*NfNp|!G9ei=eNkezrnl&AVDRC6lT#Y|@fn$zmez}o%Mj@^fiO-s6g@t%4 zjdWXyYDArD!j^x5p9Rc-*JTjAz|50 zLl)^{9{}@P^NB=ihE!`*WlygZLuAquMAhA`D>k!X76Q>lg074O;%D0_(2g>(>?eR{ z&}3+OvUsv9Ga#ChsbhAcuS#|@KYQXpf>SBV2loBrt0o8$pgx&?mpTGl>;J_|*z&QR zA6;#wAH4{iKYseRKA|7cYAcA8*dnDdN!30R?3BI_kg6SPpH<#}$jit}jS@;XaiKg-SE#I5;>C622kc zXCGfQBI>SqrySJaIdjG7t{Rr3ui5;lkhQ=gsyiE%$J<|(`x^%wx6Muz7QQ!cSSO;c zF=iu--60O7j!SSyw{s+0V!W4c_YTU}Pd?*tJ{HW?-Z*2)K&7)OczJSFUOazVMmT7! z_zYMl*hat^UVjTQaQ%{~;lS_$4QuXNEXKevX*8cHglxdxl^%O#W-v=lMu0*#46%02 zM%Qw8_7kfuM@7(Cjt%c_^~)uZ!Y^Sc7YYPoCIjQz1)vB283({1XkFjXSt*1Mq0?B2 zYBR3AdQ6BKm_$f2fXk+LqA!ZV|SP*E_C5|4MGqk^l^FrnVb@t*U#CS^s7zYJG zwK=zfI7T`#X@SriO=Du#m(WZmc)o4ipmpDDmPf4fAeht~1Vq-JtctuXedA75Bj95A4L)sq=a0p~SE)@?N8Cz0#< zYEQp(*`B+CRS;oGC`#kBxTa=6OU{922%qw&yYW>Y}=;K8DQEiWu%`@JO|7p5nQkw zl35VRXmw1G8EVdvRESabSmq+^vJTPo^-~?IC{_PjmzVke>g&U#zf#vNMN=6AL#GW0Vi}QM{ISEM(tm`n#@S;i4rkLp{uiCP0r5~>fAlnf*(+3%sP7pVg zugBCD?LD}2zkL1WH|4iq{HEO7Wz#ID?sj;m_kqp<2+#C`4|V6FF`BQ_UNi|~E)F4h z`>avjWzSO=kFO~vKFya~9A&X{@wVKVJuQ1PHs(%WWRrD=HKGn?PSSL!PWNzClR4Irqi=(#o@K)fM*BQ&@!-iV7EByAiSRzzx8z?5V^ znk}PU(1#GTXaN#$;3?CmFX~gmRv2m)a*dW`(R$%e^f66}8E42GiD_J%fTImqH}jNH zKSn-xehtU`4*0=$*0dZ0>t^;r@U2^u5GF6{LJ09lZ8ynIVPq4IJNNkY2|@tJ9F|>N z-S-G4ynTa<`W$BjLY8$f=~_;elc#eALsU`E_jAS7rQiGU~Zt)5#jjwn8vdon_cNH zpjGn+4Yrb|An)BA)djdc?5*@D+L2PcOv@AiUvKRK_w{MKTeH$zz?B*l4R}FA9>8 zUUH`p&l9$+YquqN%pH2<^dTxs2cMx9?n(@A-dwQH$e4K^3oHy^LI?y32I)trAus69 z?OzPu!?G{2`v0f|R8FT;YXu%9>EGkJQO;CB-Wi$sG@W z*YQ;dKq#X;%Mw@h6cs!`?vq0 z{Nv}p<-}7Y^VhsPpQ6b?n%&utrlla#SDN9v(VT@u%}gS`7z~2-#w(&bxVB&r%@rE= zf(X*k-ZCV7%_he)-0hr}yM5{d$EHxbC3VNV4jy&U*89xc5zjY3wrpI~q={zK;oHat zSDck4;mu@3M4dyhvz`gD9~=zJ?&qAL1rwTcto9u3bO|w(a49fl%@jc`=27P#^F(u$ zFku-!f~>-8Vn8y+{tJ!+yb*Lp%SzpHVZUIwzVh^23Rc(^h*`X`N8E_ zK*jk;@F48qyyIwF+*1^@F3&ow%}j}&e$GC<0g({8XgQiece}gg9$tyA$qlBA!zJ?# zrawDhSZ`Mb?lRFSjCSt_N46 znKSU*MdQ*5Y5-G`5zV1Ndc0X*+5-ORWT0aR)Co<9F;i3k4Ea#EaFxEyP$Uf3BU6!H z897Fn`mRgNMXwd@Rp^j;#u`AM#Fx-{;1xy#Jy#o&iDiQ|-@-O#f6|B_Dlb}ybS8^6 zfH80B)rYhu^*Yy^5Bs=4C?vosK|3RPlX;VK>U)G!aa=W{nOF_M0lgxfQlye&ja0yj zDes-gaiylSPSnZ~l}xlhR`tGZOeQKF6(OC(C~TyYv(j*3!x(d?kdV4{g|sc}mu20q zeQ@7i=@>sW>j>}w)IlH(rBouvcd{_pbPxo!wsbb>T=UvyQG9_};^gfS41$en1d{|y zYB^-fLLW>;vw`}XeVnj3yUQZtctDIe^=PPVpcMrX(KKcfy}%!hh{*ipZ0^Z{8(U(=N-;|K_)OYAH_UcP031z5MEmUkl7+kSNj+u+L=! zk4;vQcuzlAPwMVY$`mGig+cBDCUx#QB>Qk!*kV1A^~p_`PZuTufr7<_8C^jHL2F=# z8wO`7&0)G~NZXjB4902PJc%B<0-BX>#K48I(__se(l>~{uzENsuQp-UFdu@FWHH>e z2(mJFIopR$>&fVzEZ5b9iR*G|u6n5r(OTW=5i3eFC$omaTy-8~I#R8wp!@5f2vvii z9hG3g2q6jsOxIVI!`?2BaPW*DPao~ejbS)4DjH8Y{8alP&s^q8yZVI9+VE&_Ut;!J zVy@fV-r#8Wy>i$+gb8t;8EbO7`3Lb-OWLb3yFqzqD;Q26bfz&lT_0xY9II=YWL2%B zj%ZQl=N(j@XbJ97;-_P39n5J8iOJSYsA_CmM0yaPHL+dbd~ksacQ&$8Og6JpmZnC9 z2F;ajicb|(DZ{yDzQ-FB_&bm5ysv3mdar^I^JFs~SB^PpGj_m9?asB*E}Ei@Rx3i5 zC8#KLHyAGY1coU?dR}4W9F2BJIgXpO(LDSJz4fcT_d5|2oM1AdFoG~4Pg*qIl^f~= zHp)ED#S$eDU6|`yh6LDfIhCNv9la#{UNRf&_No$zzZ;nSa$ZkOBmUA>X9I`3vh)8PWD@Xn3_e} z%lxJm)*oK=S>6VA!lk|5t9R{r-mjO%yGGG%vo_x(`Y>M|jnpL$%D}8sVE_;XMot=I z#t9ek%#Eg#2}cqm4Cz)sX2OV1;;3d0C#I7$Bh52owYkuaE_2%+Ph{myev2a>9a2%v z$y1X7%D_JJ0D`fE*g9rnk!EPqIX_%Kl;|?r;0p)EA?g11+po(%{r>lS{(%GK4$2Oe zg$awz146zmFmHKO%3z9#%&;@8sc4?PQj%mnYl8^fTL$2Lh_t>B0ms@fJy%P5sK=RR zR0$%K8GO{aiHDlhfZWuz8HOs}RN$m_29ErZ8Ih1NmNGz3D8fH6`2%l5`(-BimyVI%e$eR~%z)7pS9)afP$ndt z{E*f_sRL+_G(t0*5m=0}JqPdH1YFrp6)MH|y2sKCFjtKW@4^05a zq~UR4Cr_XaE>$IfUyQkj;<;QfVjDppflucKX=!L^+L>9EzDF1%eP~k#706RYm=JYF zcqWf#KR}eZlDU-o3b%fB!=?g7KANQT(Z*q;>;O^%pfA1!E1mjY?=UqXiGk1C%504J zBnmd#-vT|1i5Im2B(OFb87R;?nMq}WGBSVD0fEfNJb%lTa>)~-L|OiB+maqNzrAn! zZ5oNUyPgHC>0LB6+&W`K`lq&=I6Ppn8JLcVq@amZSo1n*l_Z2w&Z!|YCH(4T`~9R(jDeG*mPbER zD8*X#ZAtm@L7CR_splUg`zwC_rS`5D;pA-r| z;ehV$@0H(t{cZXB%P-28pMO>!bDZ`8Yc~eIRILj^v5 z%a~?(s%>xWm;ERA$`TXUUXG@3S@S__c5VwsIDbHqwv=&G?M(QIaw3Gr@@;HuC@r4VRvlkp;H=nX7~J28=e zv^Q_~mU#&$BkJ3(9&18sI*zLzq)O^j0uv}Ox}2`A#A(v zX=i|?gXY}n?w3dXhvi=P9uX4uSSzDHz!dgEUO#D7zSBrM=#{zUhS!GR@>o2yP0lNY z8nqxDEficKM&OjfDjEkkphlB!^Ghye<%cG0u)es3i~0_*z$+ssdk0XrB-^t6-1-AO7k)&8Q8ielEI)%8)P|N-is^} zA1Aj=z&t+l)!%bjrtS7y;P6B$L?ZW8gXG9uH~ zXQE1FK2}{3+8yIcb(ZOPIKjgl`0b>T0k=*wlw@J`tNGg$&9Ak_cx(RPgso`XM4ikL z;eLbD1JoxIaS!cva(D+9ecY!BdGien$j@hw9}+4@rU>B&{#on5{HI?^)=`;fC?sXD zi?+cY5d&M!VN!EUMC{3Atpx!DVQ-1)?}q5m7y=Vzzzv|ML<=9_ioLzdarBs%I_`5Z z4w^2#XbKbTdk=LWh(HDYgUbn}2t&r(jhz#qfWG^ zA(|-B;E?jiIp`I0E2iB!@!v4IPGLls;KmfZ z(*b0O`A@jEK}TbPL*kt?-fHAJV$l51j?ga}%S?#YwZWJl9I!zf7&=Zn2uTCzjGD6= z^A&k7p+nvqUdnx5Q_Ex=WFR_|csW)^Xi&HfV!krZAt&v?Ky@O1o{@##ypb-}`Zqv1&^d zVJSNAeHJb&hxHkgA$cSuw91c@rM=SO_Qxl_EibCEh|+vamNw8Hfzk+Iw9~qj1Zx{j zSM8-$6@QoCRzNt=f@BhYG@&?2v^_gXlsqRgAp(=WW&u=0G_Ydesz@($YcU%bSvHji z-WgEfr8k%iJ_qY%qFSqM^SfSax9y{R3zwMV=#OJz`7RbNvMaC2yIxR}Tey7c^6C1! z3O^tEyb^*B^CgWBn{m(kwc>wu>~3LWuGF4>TW0MG3#s6heH33@Yw&qa!4*rWvtGhW zczdl?ULUOewGVBcwa4D3kBp5Ih;dL@&@2mJL6BP4SD$@T{_*#}E&uSl-;_HzvkW4H z;AV{mt;d-jauRHbgNw=4MHeB%u~D1GJf!*O2A5nn9HQiu4o)g_#_tkOsucuNA~$4h za1-;~&UB|-ApPGQJu4eK_aJ%`m=JAs-k)&wR(l&GG6-UUs_LDUs7*xEn zAkfzYN4;?|3f%0VJ!xK>VuCwk@5%6B6Ri>^Bol;=zrpFI!`cbrGw#O19%3YTAZRN- zXJ{%ek_-EoaUkw)h|PjGW3a&Nspp&k)p=*AWG-+eI_uMc{FzIcuT`4~yy;c;b!k}u z4;;-I-f=s1(Mz^H>gukqsmz6+pQC>M&+q%+n)$o7tgN_Bjaf;pnrN z;U?_QlKX4H4Q-&7Sa@V&wDUs@3F8K4t5`&s_Yz_8O*0~iRdi%N_Br&9`el$a;F8VH z=_`x`+OdEE;fPmexX637#TAYvXSiJ()g1rLayh^a8@T)KnoULOPKi0k9MJ6PM&LOD zj#|)yH17M-9IqmvlCeNg)0v?Q4)5SgX2F|7bB$W$a2XTyEb%1 zyG~h)dd(R`FNnhJ8Bk2P2x2za(pgPsF`dO zL&R^Gl^k6_G653CBz4rXbabe;$fmN?`2L??A|Nup5G(8CBSJ+jCcAC&olLe8RgtAK zN*R(8TH9|KO(kYb9ta-hb5erLA{>|BF%x0!);w+SL=Vr}Vi)<4wTV9cGrfIwzesWm zBW_#bW*>xs?vxI&<{M3(F1qUoA_CdwWXc!`k59uSFt%*|)vgQo+E3rLV_@6=zRNOd z`~RB!w$fhzJy*>~Klmq%95ef6*M(PZ?URM`zOBo5eu9f@2>(~Nfr47$Aazrb^F&5s zo&NdeYnabJ{A2m*i_glFhxf}qV-?22bi2W{rcFNf7l{J@viZ{W1&qI_r{5j~T!^Ig6N&sotu1eHxTkKY|Dv!rzO!K79!r+RGRvY5vs2KCclI zXoL-C1pQwpFazhWOmWgz8*8goU~U5|?VO0z67F^&427?0NhVg!YnG`=PY_UQ(}^SU-;)lL9CvV=!AHBwe47~f6`=5Pp=9#}G~Eo{3UzBPalI5mQxRwj)7STBEK zZpgPASM@x^O_(xuH}+Tqz1ylbS(%Vh78N!~Zh@b^D!8ilAVHN7{9V^a*=#_2`Lg-l zq-#K&1RrJ1)AjsqIlu5tCz86UMuhcN{BZnyDc(8`5vCjj9)?+&mroTSexdvi9+N!z z{hNGEXM#)C$K^yFBba>i)mP>J_}~9GCMZWGAbDRRG0qsjE|b+0M0*GyaYAug*=Puf z%~OkjYJn3~*zv$bN<}N7A2=2Chzi}qp~Ovy$7nno-3Kun-56>bJaeJgxQ0_SlS|BU zBaRukjb=bm*AODtpYCzQ1$%eP1Bk6_lwqK1AZS3=T{R$0=5QCc>`UZm7Y0L!AZ=#7 z$2e{}c&O!zKHP%jJQEew&>0WciYKgtxYl*ao)+gaFDTc(ato6C?HY38x@GQB2P5ft zQUd?DEE~}H%pWd}TfPs~uB0i_85^RM?^>u+a9cUE-GYyB;P!*5Ax? z+8J7jfStZ%@X1X2YR;!!(pH#|F74N>|4H{i0nD!aCcoz^X`Vxej#+F*-diR__Anyg zuPN^akI|*uNO<0-&c1>LeHB-zG4xDYEM1YQxP4#<{5GX8nBi=S&K)bPFJbQF^&r4& zwHq{ZoqV=%xja)VLn!jN6hmGqsB4b1zxF>2kCF8L!^@#`EQL{kmcedPrR%gpNhe4F zf|yPXC8jmhS*3HmimmasS2l{!rc9x=EXw4@QQ zK&*!7gUu<^&UplZ`Q15flwpz4%FOHYT3Y>^g4g~y859nBm@}67RL#sb$6N*BaI@Qj zHp^_RPZwKy!uv|tG>PpX1$Z3pIqGK|F|adh19j3-d?t{Rt+vugZ@_5)B6y1D782|k zJK5cRu8wZKBB-p7p9peDDBMRQ5@E=j4QKRB2COz@yCfh(;3MpvXrfmNAa4c2yMeE; ztuVJf;S>hMw}iT$gOX`)?oVDRjr3lWKpE@Fgm+smcX?SSq{CkkO-+$|^EG3-@dENn!MUFTTRv!ZTKA9=X;sF#HLnP%UExBecqOsVr#kFrVODQ0x40G@U^E6)(u6@*4diD=t%epX)X|~i8EwB`xFj@O74$6q69ZK^4 z>&SRhrcp;=z7kG`NSIt=3Xc`kWmk8-k4 zheErkbsb_1E%8F##2Ml7_7`P$cF2A$eAXxWoUI*%B#KdLJO-w@5nc#zWmj%gvjYJKQf4Mi}i=T+uYtC`RY5hSHG- zYXR%-lEh_*qWBQA->XP;g=+LkUyVq<{0(J?_@lroq_hC&2Zl~x3MScjw1iNQO|H7n z4Iz%)R(z$0RHcyG^?{+&@fH}$QV<1)z~f>p z-7_TU#n?ha11qH)7*^38k~hZLXPGJ+b4=Lqd(RL9)$6wO6Z zs2ZhJa`4jSO+=;7&m87@tIU2R2uuxUu0z46O%jT48srS&pr^nbIS!hl9-vVbU*+d# z&ZHdA1hTO|e!2B%0q06nsr?*Sa`6)Qg*M=%VSu^DoH!&)MZk;@SgICbpXyUT%zFWR1dstRbgf9W`{CnwmIf z=*-h)p2$SCjSKQ(Bww8}CnI|^w6rT8s!tpo!kbT9v{W`4t(NiY@q8mYfp5xJM~`{z zv6(ZlKVdKff!!-30#=#Z4{ z8}fqFQQ747#6wSs0ot5htg`|vFRc2WP|XWR1)&4H{iTRt=B|HS%wZu?Iw4rh_A7Z) zHx5e4Lkz%!F$%{0Z0WN%hDF_}e(x~t%4)=1#mHoCC-h^4IR-mp(065s)ThmTmx#+x z)@yMK1C-&jBSQPb@@~<_^hocC198`$d((@~ZrYJc%e+l=jW(2>%QJ^_-3{4!{fMKd zV~;ux)q@KMRWHoE6Rs1p)FYKL>~=@K(RD|R(B0W6l|x+f@EK^ACRb zU64W}WU3=^%Y+n>Fn2(BAE{h~I@C#`bOAGds5`njid5rbgv8gdjx;$4hcBMim|!6D zN_Z{>TVZR4W)%=ap(|S%dLJb~IcJP8_{8T*#fo@q!h&z1wdPZi6fsP|pv-es{+0nO*O$0$VSL5||vn9vURPW7|`p{-6>tJD# zUQ9_Pt@*^KF*3SeI`T)B)M?zZ?mQB7yATJ6_jP_)v~hg3sqa>HO(w z7e8$}@7(k9(YKRpIKvkCdcBMApSPS?x7ODV*2W%eXu9tsu(%@C=#k z%ZK{zyEEHO-J5n316ErBWgW7*j^4_6Ti)&n<|pf{-RIg-@4-bp?b>aKjw#ZUU?hgF z(F0O8o)0AyO;n2=%nxnOl3v@>JZN|)^s63t6gs11o0yv44UKCEHRV}STth`MfE*`E zZ$sLaURy1oP)rK8C_x*j7efQzN;qCUW5f`RmI|e`ohVee5cb{aMQC4E@MXPo8K5Kf zng`l49lb7J){PQBB)y|U(o3psb6|~D$t}OXahaF}qdFqj_?`2X(aB@|Mh2jU-m>gH zDn3p^aAZ*OHQ*iT`E1Wi!&bfR@GYhA+Pur{8S*k0RBb){*_#!8>P}M2D94fTneoFi zZhGt?o2QfVNs>deI?@j1-wd3PVY+^2KG6}n;g=ykY({^dm$~KZU!P7o{_A;t;DqV; z;>`h9X`E6$khji`9^k>EJH1;sLVJgG$A6_(rVd=W=bG=qTGojNtk0?!QJX@Ww;C3YVbv^%%Q$L0B2y25H z&!oxWJ&6kHJFe#VVnxUNjhwN(oSvc&ISkKBK}N0MnV$Bvr)39( zlga_vm5Es^oG3xwIUd~~@7+DPRc#llPpi!aXniTu@byiHj#wf@jduxAdHQujWGVK*;3-=Af} zdv>J<6NQo@6<-RB0xA4N27kLn)aSy})2?f~J?lE8cj2X613>!jrGP0Z)rnpZ#&UHs zOu><7#TkN(K@8q@T&P}sk_5XfY)B7}&d75^*|kbAdGz|~#m=+~E6jZJNt?462l?vr zEIjNyrzPs8$MhdU>>P5Zhf^u@kd&cuc(E=k%+^P#ud8vy%r)=Mr_%F6>Pd&5majIQ zIBncvW6~Jq7&$?}2=5F$_z{9hwks+bW0yg@HKD3KU%1AHk);sT*j=cG%k~KZ( zouT)Rl;L0iw`a)hwhZ_B1iY8#>Cj%DU3AG$I2K+Rpfx8x^kvl_AJ72Z`r2iJyhWY@ zG9nJCUQa5^_xevHc=lVO|f*$H=d_VPOBsN?gQW~-HMj}(L^ zfv@rER#%-81xG_3Y-D}MrQpSIl@Z!pJ)%+`DjeL4=7T^p3DA0l-ep`X>8L-0E<7X+ zlO5a+<9g-3k76*T zlwN_=bGu`J_QcS+-jp74HZrh0AuzHVNsPh~*&OtUEt$iJ(lSJ27i>E^Y|dQHp&5en zb=1wrY{?4BqtkZN^GRJSTF`C}%^q?4yr`LcwF3cf8e&9&Cgm2#v$k}5edKsOBa~x( z<|xcxm?+G?#jEo3#qW5M$J9%0c6i>`Q(G!7#!iF-d!K6|QoF0@w3mFbIClz&@GV?s| zFXd&Itccq@ZP{?*bovobn2z4PWm>mAhH+ooSCn}+;T!PU2pOe7FFYj8t{o|_6lgBj z4s$|qOxOg6z2QL_pbWR|ih@57mf_PV;H>V8?u;{XL>z(5;qMXIas9XrM@=UkmimN_yHoBV`EJX;mBa_nInqCfmSeAWQUi`f$J=Oadz#R8vBJg8@kF8?oEbCLkfIh zkb20{_CXsXzoRpOOfwDew@P(J%49~)+|m#WS|UABW4@_?iC8IPp1m)Um z30;lxADO+W;{1$72Wce5kF@D#%y{1_erForZmZ#fkA9}{eQz!6F2f5QHM?TqOy3lS zWy_(APzorc8G75u6~00!n%_Z#idg<(U{~N&84EC%lhp-&BzQj4-TmU>aR*82*$l6* z)urmu2_L~(USScn<#HF`k5r@Fx=x}(wI9r9HNgWtAhPLAN!%;Lph*exnlr>v?Yk6C%0)OzvAo^L zV5(4Zyfg3V*f-IflU{#q)~Wp@rS@R;-ma|Ns=fB2C(w4cRacxh1~bOW6o4L2eatej z)j@lyo)AM+MjgJPYnZ@E6h=E9br{nKseAN{IqH)Cw9!yJ#wf-vLv9<^<<-=~kDrb? z8!tD&(W)X;0ep!&O&K`d&@HZ|UmGbU%o+l#a#A1lO+E(&RShN{l{d{F zjBqPZ!}3BHCu*I3nJ9<&5Bc&mH$PzvQ-r%r|q zswc(}rSaBFm=VGnuZG!YuM09OUL8!@@aGk&^mjnn6;?Ju}9Uiq%P53(mc<8n2s+~M5pjxzUl`h77t z#|4!`@~+wL5H)JJ94DTvjdTw&Oq=;6#%Du}00pG!W*?tvV}^h?Za;Fm|K1~NuIYj5 zHKfhO%G{roQ1&$RF42xSJN0s6dOP0kv8nO{fuCWCl3hGvz_4&%+FcrJ$$3V)Vo2aG zCUO-om}Cw4(N>4Hk&ZFin0t#MLg3UTMkt15BS&)}tg|rFDP@QL)$<{%6nT1M+C<4` z5HWdP&O+K2Hj#1dZC{L(crR|2)0jGt2ScQ`=*i|ZS!sG~UYW?}FY;3GzRaaOkkzXJ z7@nsmQZyPys8+I3ssw~=I10Oxv+OhuL z>CSa=T-N7{r!ho#XK2m~sOiMy{hti`>QyKsbvi8Ha`L%~4bdrjXq#fFH)X-WVR2H9 z$U>3~yk?)j^oC++4vSO0$%?+r`8|*&+GzDabn#xgBrhd$cV;g08&<`H3A>`dcSe2<%UM-t9?92kBOdi05`qt%GV?1aE6dhQbfN2B z^@uKHqE=n!ntsEd4nubhy6W{FvdPd zjp;_{OL^-JrQ&hl9v}cAj2;HXYl3SinW|rYLYU-UpYcsYAhmZ=5x<$5bN(zJw#j6z z)`%jn9+lchV2r{0tb%uS43#k)6zkXoQH4gOaxp@fTFY#e9VUCzdine5bWI4eE9F%W zJPf6v$Cf5TQQP4f(+)erxO{pd+2+_z*Swq~V^om&fz)$dhDOkZvVSm&+^)fC-)VqW z9Hn;?CLC@HpA5sSk8v@)86t*OYFxfU@C}0!$6M43x+h&>J)liB*_iU)t5D^y0TiN%_7G<58crh%rSAJt4A_%9N}!Ih-s?9$tqWmSy6R zd5)ox4GM=$)rwLcc|K3EH(jjwU8U?X4t@4U$?Dl)o{v@TO_M|8DV07A^7{Bc? z@;leX`}Y|S{7-Yt*Z-29a78M}N1->Evn(&UEdw+gqIySCS9ZS;DU8FsBVW0_@BYlC zWY}#-dO`O%$MEc07hSqBE8Ps6Wt*o5gZuq?N6G%3zFcrv=J?3Zt}IsZ84*KaUVPu1 z9@4&y+HiKQiiE1&$nnjK$%p1ukO#7hdhN83wtjzTaQ{6qa52L6fz#_W<-xEV5{LGr z$nR};-ag%XcjkTq%={#0ixID_n^LYGGY5toSQJBF7LRha2EYythW6IQ0b+=>zuNMt z+B~U8zwt|c(OM8Ye#ez|a>#o>_{9)+5ZJgLL9+kZ_?X?M3_on2zLD`u+hdr^sTD3! z@Qg|?(bfafZR_r`VlXfG&uHX2H#RjbVx+O@atp=SAmCP-S~(MZz$)vRXC^qUW%uHy zx3dic=q*SC*W?VK94_ae9LB1!=tpqMF;=!k@D!L(igC_YNECe-p>%n(g^H!LzOS@> zd-haGI5KYm%47A^t{oZIk1!gBEO-RKo6n3;gpB8Fj_4cT%sx>0c8o1Xc-*C+0)rtk z{>!uSCi30i_-1H+Pd!RoU0Lh0a9hee-_oM4#lGJr%1Yij2h*%9R&!kOoGVxvY zTS%snQ1xYmq|1G!sh`T4pOu^DxhHz;<#gqG&?5Imn>bw=PTd#Y*;w=wpZa8Ycu#Ox z7kM~hy7jiN*Yf7H)hJpAU1_g7?znThFF5YW zyKS}&%2@HVG0xQHn{P>dqfDaE?}?l_c4cT$9U_u(k|LXtL7j&(YQb9@!^! zv*5s{$u$fYNaQ%h4p?PGf=B6uf%joqg?MLp@ZeqBrdv1c%-2%mG^TP^!;N7fWT%T# z0SxT`wS?t4)m&>s)%KE>2j7bYDq$s#B*rP&aesKQJG3>wmsN2)vi$M>^l~kMUZ&IT zI634ZM&g(_@<+y~tlyX&%F{-Rw{%;q;ZgTxC^5aE&2fa|l0>djzwl#&=edq#l%e*5 zbXNJNw>3?-WytUP`);3Z4IXzskX_DG*2eUjtUBJ89?|+cHcfYK|HgDj=6s?>(?jL_ zL^kU${M4dC3T#1l9N3DC} zX@{-Er;wzN^^J*1Wq`2K#8@&R)j-Qa$Gb^=3gXDT0zxV70&4zoF+z<;27Yj@N=hRw z#umI>6QCkMh&&X7yyJQBjn$9il5VFLK&2yq6>_nBoe0;}NcwTgEwN9$h7Ojx3MGRs z@(j$-IB9B>CWdzupdszt89efQQy2+v4IvIeGT72bddfZZ3vEKOFb&bP?z~aIGi&~h zqi24}Dj|honEuJ=9huyYGD^Wd-gacV%#4r;az+!4c!rJ|_H2R$(sGyyP=+OuaMW-( z2yi68YO`#7a$QPUy>s1R@w(&c930T6L%|>9>8R!NFdhqu=O=hj%DGxLONHT|Uh%QV=9AA+ z2=I`;(ngRB!#$W63zH#Uc^XxWQ0*BQJZhc+RuM*c*2fmR?lUHK;J{N37@69YVKXlZ z9+ShnLWaNeus!FnSgm9v05cgTxK*P^Cq3>c>kVJt~qqj)_tE7&X$ zh`BY`km0zrD~(16DEABvd9U`7XpcCmXskVqYA_OkPag!K3{=Eng$5@r1~u)YMOD5I z0afryAUkqCtA@1Qo|F|GS@1ZW1`|ekv+o30LP#;U>FBLF&!!mh!?OhYxb?^9>r44A zm=6ao6gnIjYIjy>^|Vv;dBB%;mdHeqN57Gmx|7CJqd{>@GbE>nx+}x*S^rkbKCRH6 z4dbx!s?;$~xMm4>002M$Nkl!+sgLN!dHon~{HGm}TQxz0UYF)hl8=IByO;5)2*F z1cRW%2&I(7XI{v`(x??!?3-JVNg_#i` z`U`(%O1my05jO{U`lx3!z)_V>)B-|zk2pdNt~@PNlz78;UFGJvIAy1EQ~0HQRh;Lm z%b82uFCKmslsDI*;V&AYN&}z4lPW8EDVeHGSD6J1JUFRK;7Ox1p-#~wVQe!rk;za! zxfqwxljOf(Z2nTXhAmCK{1t%a9BdYA1HziGnhCaOgt{kL_^$EOikH%cYB?qphimEc z6Et(mMgB)q8gcNdhtjPIi_Zw90M43WjR$B)fp<7C$x2LJVSI<>0!Q3vBzXv4{>65Z z&hkjl=ulu7p9rqVrORrwoNYH#LpwPW8*pIOJ)j!qOyokX zB5NA29&r>&WXX`+p&5QLk<4K#uEm)tP=TgbHF_uTOl&nIBuL7@@@38qIa_uNr|97t zR;e+1=p@wmeV#`jMRi4XlSVp6MaUB*;o~eQYSd@M*R}L>nt&_kRU6f&DsRr>h50mY z@+<4=&}rn+K9%9RV5O~9T;dC-PBQ~3e{Tj#pJ+B5uR~%{GqVzfZhF5ZU8Y&N2D6gu zhBIRp>MmcwzKzh#kxISV2uU~8dZsC&1svhlQ1r=>NrKq;7!||hshIi0LvwB3%$y(t zG~kc2;pX!q6DKAHhhJdn;bV^p)aEWCACx?%G zW+4=zNC73>!NK+DRSbAwigP^DP(2Tci?Auv<-!4zR&hhnMw&{v>W2ug4hP1hF8NzK ztfcO%KChjA?bw+W^-x)LpP$vRns#eLIWSgZaug48MsG0ohoga!fmsEm(3&()x>{g5 zBLOGDEp9c(+*1b~(A*u*UmAwTeI135UeGXp<|0a-@~{@jq)fx&9Y|c~?Q4yua7bDT zhkQyyRw<`?nz-V<{2~*QJg~{{xc4ic0M9O`+Y#qWL6s&y^?W|dvl!G6{6frw$~51u zDz9!A;8eCbO_kC4mv0((iSRRZOkp1HABNoEqA*gs>iBUMBeb#}R2*?qj6e5<*?b<) zI|jWRO48o!^ES}sEOgp|!D6ZMRKk&@(vI?5Mn>s!jxr3VHGfhw9RGoFz>UU5Z-?RfD=Me$Njo{|qEOyi9!O>4+Q( zZ@Iyd%DH$$6z;sK?AnV@l?!tl$p9(jDc#jU0TL$g`oJ(;RTdN%YE?-ksx-=VH-hJ~ zM{oy-syQWI6N?jSv43kpGUzzbqK$!W+~hPn7U3?1}^X#G^^TG4S!tV9%t{f>}_PJBi15!y z4uSW9JlE!`p!`?{uO5jUHOXAi*nTEuC4DhMZoWCN=SEoIq+eaD#wO=gj~1TPzwjThJ*{5R zez0;=_em4xlB1HW;NHV7o{#Z=3EkuwDNqh@vat*q<;7S z1@OmdIepbFcjEiEF7s0;^i7=;1I9?alA!OCX5n&;{CQqL2aw`)8dxc;0_ve>qX8Za z)|_g_%-tw=7P&e8z*Ex@{ap8b<)7o)fDhgb44U4Zr}8J$3LfFpT->ZW#?vIA52Yko z<8t5&*8FJBnfQ*AV9Gdf% zD}YlvVPvg1;0od8(?~lJMY83=@9Kh6saaANovG|;O@!BTcQ&0;@fMpdo%5J$Bd=GSnAz>kT;P&mf;*s(a}CQ&oqCNSvBU@8ng|jPMMP|5=FFvkKpIs@ zqJ&%<(ygxzTjiUDWwz)!)cj%c8?tS~r;fGCI8JrFvlvjyZCcQ{x7~Vc>EP{I$l@!~ zrNaZK+s7y~g`#iaw}MQg3#XOX%2D;t=We{FmPh3^spCjiOv&Y3&sqKlb16%20we8+ z82|?&L})fHbM%1GzsZ4NLbyTv3+YH~E#*sx@w{`+o1XXl=S^pxdB${1cCo%QTTHz3 zo$s7}?+<>jhAJvALgk`YxKv#KV4N_Y>RP=<)dqtXl9ZgqT@WRSvrQD;EyGVFgM%&v z&D-&mjJjB8;F{nVD;*?E27pyngq}&x>&+}Cde*gdJsQ?%2!(p`$U@!-0{ZO7?0^(n zNEV;9w>MIZU&=sjj5mWhYB4`sOt^5JWXqwryxbTel}9rz>RQSfNBKNP3pH8{%XfKJ zD>1Ep3BAmPmB*ZT%ku+lRZej$VHu88`LE%EmB^KZ^A$R^fk7YFj;5bpqkHo`o;MAh z7kiWgi&4;!8Ffs3=dy!-)mz>CsfD&7SGXi*{F3NN5zNt^>VxLl4aHA~`(pQjU>p&?DDLBaiu8xb4o$*jywX zjt&0Qt0Z&TRhOcZBzQ4Y1f`x1aOJ8xgim_9R>27+32<;BYDC9)q?Dpn%B%e28C;J) z{`l!}k9%A`TzB+z>f=tEE`9d1rsIw~uD*=0&ir&r^BE2s&mNXtF08aX)VHCk-f0h+ zmqvH1`u^g7{?F+hZ+qMH+0R@v-F@esMQc5_8VQry_!bP*F8WHVU)TfUQSti*owur%%V9c*1nf zIcHB7TzLNUm~0lgIfU{3iX*d@9sxi0v5!ul|NQ6j(%`+Bw6|T({y`nUc5*B~AH{iC zc(4VY3nN|dBTyqMk^QtILM|-#)geF1 zTO%|aMryoAlSCQl($G9&m5ycaWWXiVYu2rxvv*~ zQ(%>!pDKGsfKhT;w4LL|yyC!Pq<;{qi%BI*C3P?T%Dd5W~1h*ZE8RP;Yt1heZtK!@)XI#E0 z{5?Q-rE>wHF_v?41P0Esm)D)NHV7Wi7vL0qk}>DOW6%~%gWw8c~#|eyRVsc=3d~u)gqU`>w49L!g5?a z+;3dJ7$HH;67~l);`aZQaESDXpEK^CXyI<G$m#K?KW=)}cf4}C z;>s(gv(GsvRypfD8Fz5JywpMLq5|DWlbcikNWbVI!Z(a9DHthy+* zh?%oA?fvo^svDXF6ils1i!^kN2<2Je<}9ia1z#FDVJ&#|AU|UWAU%>9w(VS6`4`z1GY@bh z>q5NCO4~r!I5*v#)umS$_EPtz8(HXUU~1WX&hluO{etvJH#~FI&EpC@Jot#KF?aOA zM{y$SKjl|EFVlzSvVtn*N+-TPmY8%k#0zkG1U%=l5CNq913s66%%YxL7T-xSF=gPO zMy`3h2a-_FV94^|@i4;bSDt$SQbNUZ^HEjwfjI1s(YJP|+?J{SOuPDew+$YH4$&Fa z9>%iZ!c~1{!uMIp_%~{d2ASV5f1Pv|K<@wtwnFTheys~~B>GPtrO6h-qhj1=xAq#V4ho?UL$ z%M1RLik=T4J0Z^c54`TR)0J0USzkV7{8U2kwrCI-1H%MIBELg=RP;xeB({|u8=w9t-1>l4^8)P%L!YiCqD6s(~~c}Xgck*({em+dg7CwG@W|tsj5>UvR;6VZI4- zN9LEV`|7pR2R`_L>4tn;gCEq2qZ-8;)k9=VdHmxaKRx%d%cd`W@r%=kKK!9#KyelZ zI2^(C?RLGmOD?`-+Md0}u73AB^U~Vz9LVj=>yd59a|Ax|5rnhOK5M%CxzC;MyyLFv zt~>9lcSVj)ciLOk8W813(48s9yRwzcO*h>%ed<%6n!ftgua;nVzvKx|c*69g&~#~O zX}bIFyQgcfy>|NWhd*5VpEbU!*;TDG{0|a39pq0B4W9DUr{>cJ=hocaN7Fm~^k+UZ zec=nAukVkPF{0ttfCulR)AK#+th1(PKkHew7uyZj-!Ogp)1R7d@!9GweP(jGN{%*m#J(W1fL>qu%2%c@ed$Z}J{I10(C{e&9~Qjqvgb_CeC9JU%=19pz2`Kp(7Q?+c z^PAU4-YJjaqJ?afiTdZ@wGXH{H%%(a`+Hf8TR88XE_%vSrzeG`w`T1A=9_MwZrHZ1 zUVt50Mk@i|QeQ7UlC|S9T=TpazF;~n?TO;~zz5zx{pDZ&W#J*6g)F69BAa7NoYodi zrEzYwIu?2l7oa_QH9nPc=ycUpS54=ge|{~4H_~zS)mP_J75CN$)EEj4#11IcKBI(J zc(qVk(lA`5KV}4u%GZfcIpwi|f914w>r&C{-S577`inQexp+l=GFI?eR-~zrmn-!o zPJQgD(_>D4%yiO8Cq{O%Eofv&Vmr!ckM)jL$}(E>*(m7uyyv}nAJE3kpg zJ3q^?-U=@o__ucUVcF%dd=01No8`x=E*>_){^?UW#^=;iPMOY(0lMVki>K#a{@m&G zG=LLNIw?%ECD0&7b)gYpCXNPUae@~&?>7XO`$0TtV(;3)lT%K8>~zK%Pna%!=B3kf zp8cHZxzD|Py78tPOKI=Qn{>9n_t?^J<4-t#dfHQ;HofANubfW( z_$TsG;qLn828E=-*z$rx+H(8}(^==7JH6;7FPZL*5xO^TrZYx{2Pig7u6In5HkYF( zlu8iXi!Zr&diCG_+tb&gkZ-%?w(R75LUp|fCWSb5tr)vOXaKiGD8BsVFP9)_2;gts zx^;S16#ONZTv9tgOY`Z^e7b1Jc;0f$Ee8_p;6zN?&?ADV0qXw4@yaNTXFmNIaU4#W zPI=s^(~;Rde0O;BwJ5-EW`~Ut4g?D4)6(;OdX)OBzw5hVZ0{)L3^p8ZzB${=XP1Kg zCm z7nOJZ=}&*UKJfLqC>(SoV|Z?2cgyj|O{biE>U8-PS4>yrxa4V<)O%ik^;dtD52|4hrgNh7UmiL<@tm`&7r@aWLwDbi zFA3*7-hhwHQtpMv0wZR~&a? z%GYnZHtpbR*)A))Plq1mRHB!T z`F5tr6%lG0m5fC`ZqEnn?#(V49@qh(YsgPD687Q zxJ>SEEu<$@XwA6>$d>m<1amR_LzGSFJ|l|fdC$9QdP=-D6J~^jVi-n6r9+FrQ=zn! zA|OK8V&k@KLvqbE*G%t=r}p8Gex$5%;g_Tb!_x%ut6ufDa=faP&xz^69-i$>9=~+@ zbks3NPDdPdL^Z}g_=De{?#Nar^(Dlr!-17L;^-sO$X_}=KMN+F{*0%mM|I)!{1-fb zdh6TYI=%1x@0&hz&1Y(pONMmo($e(wbYCwz_q+(mmg$+f-k$ALc4iwDD^`3sZDY># z4ea}SOx^|2>pAH$Cr#&OafU5p^mZskLZlbr5YR}R$;YLXN3l`x8i`L2JnwnWs|N1g zH*rqO#N?T0K5=^E8~=3rt=GT4VAPK`eNYPK39qw~?5jDupZdRlDj#^ecy6rOK_CtH z+0T0RbX*$3NhdvKde=MNF}?5V_Y~;0e&F+zr#xkP`Xx^fAC{&kEN#s~lyfq^{p{(z z?|bj`E5H29(@kky`-$bc{ZTAKv;e&2bs_42ONxo1J0(ug-ckY{ZOp%1=)x+gNXU*42OdD^G!yI%8}=~dtP z>gh32dYf%Sm6YH2ecu;H?b*|xz46bczkJ{Or>}hV%h?0X7x#b}E}_duCt&K7_Vj}3 zM}F)_!;@1=rp6HcmDBm>pF6$#T~|-)K z!56;xh11g`s~6;JxF?=;Lh7CU{_^*?{?@C~6TWczrC<8R>CJC>bJb6e37=mQ$MM;5 zR((m=JT#fS*?v^*oa;XUtr-*okR-ZOpj6Q7)Jv7$GQ?&wtv z=b^D*JRg~__g)p<@|@>9dwOcx2j}P5%;Q*fbHN1{O+WK9Ka;lm#_3mo_1ChC`}R8C z`HpvH&U|xya=xYrLefDIQZqhIx-*{)An=9fSKK<#J#Je~njWQb`9uSP1rt24P@zxOI=C9o}-JSU#736h( z`O9Ca9*pO}69hzB4B$Tg@k^z6Pfj=b#V>hrmC4xI@&s1ABxCYROG~Ac>`qVuoVu3B zkVHI)#o$9-7hQN^^@L7}_qHj-9Y*!-sl%J9q5N zs+66zJv+lf8I&+Ykqoa`eZtnJ+d{SA2A@6~7P6CqJ*IYLH{~5MZhA@-DrID-%TOF| zz6I{c3`rgr1$ys&_fB`Er}F6x-(7dzb*W;wo-)Vydn%rP3bN=C95jYA&p0DSW=k6L z`BBVQOiNq0RzA4Ods2F`J5s+JAAdu6kwv#<{BzOQNvlDhn_l8M8LB!a2KUg=eoH1< zj|%?VGVIX98;i7G&c9#e$_?;A`(Xo`G1lsa9uy6_IrI<(_!$Z+@z7rfvFk)5ZP zmx@Q`ZtlA;yC7#H+xtUz3h0b8;wi^Ver%MvJeOX2Y3h&_M!{&%b=~xs$PSpNoO)W| zZ>|QcED{FyO?ggM87ne_r|*p-`^)#gKd;Zt^joZ?>k8S$A*-3x<)p~jV*^9Dy9YL9g*96@7-SXG7nKJ zRP!9H5!RK_I58g{JontQV~n3xqXF8%=_w2U1a0i}@awqrI=luVKY3VM+M1rn%R-yy zmXl#HJho+CF=NxNNy*VQjCw-m6C`-36Qwx5wRiK<|3jyQ=r2QHnQNxo1zh<$*0PV$?)x;V=-<+j((3 zpsS(~o*l1_BBu0P*o@tGUaRXINCao_3h&(LZY~o$DSYRI=T3l)7b}hTYuwi4@>|~W z)^v|=t_2EDe8L&iGh%FyipSYOkAbiZ4|tA6pc?9Mp}fI2xDLZKj3Ru+wZU$GJ z)&dW>p`V`O_6%FvCZ~ct!R65m6o+{r4X^{FgI;bs;WJlmZs+A#}-}~J+ zOdtNpN9q}``4umJ#dL8LDq~FE$Rs7%Jya4seZwe0*uANg=LMa^&sryzg+D-e_fyeg+Fd^zs8W0xnKPl+*l;R|0>8~%PR z&YRR0zj&Aa!b_eq{md`?T-6gls#<`};jj!ZUHSYgv*Z2x=^gKUN6kY7gFHPrFABE? zu-|zYVtGefYP>hpoZQdUhaG zIwi)G{Jr|s-#Puz5C3p_HQ8A%@szOHz5Cr= zrTy}e2|fRR@=tzxIxF%u1Z317?jQQ_N2brk`T9zRqLoQ*=Z$Mh)*4U1TQ4?V&UjU= zwU~x8gTE`tj4QFLo-8MEaYzFl$(liZmZYyA3XF6kpjRV#%T<-TzTb{>CQfJjk5nk12h@`!mQcK9~brptd^CNPcf8(L^Q zEeiNdChsj6U<@<>^H9cM)sOP>j8{$|luzi*C!h;sLkJ0q)jb3r?u1M}-lM#{yXsAZ zG++7ZSBi#uNab0kAslJgA@EHCUyuplZJ9$*4n+f3fsk+Ay0zv)81kp37kgrc8sJzo z3T{$*r>FDq1eYGal-<8Ggb*1Rprj%Y<77zi+;h*X&tz|&oe}b~JN5c-JTjBwaG5hF z)3+a*k03GB#_sRA_nx}m=yM_AIa-GTivFkA1v6 z%h&$EYs;HA{E6-ite{MAyKH9)@{AZ?^rt>!t&4_8b9DG-2$sCstzOWh`u^|#{(3*o zoS(#lJN3AJ(D?Y{PbdTE^Aa7ZHy61e59;uWSG=OUdpKPbPn&`yV|wRb`tp}b{>CnNI2GoKizNzc%?vK}bo zj>hI#^o-3DYnO(&UXWpLvVU6{q8$+r3kiyfDSU5@e4LZs^~D!It>&8XPJ0l@GQu@4 zw4dgWWzP6U$LI;a{`J3IZQXD&!^P3F@CRS;_9JmTv}0-U^PCJLbNs+)1EkD7!F5OE zSiJ~812pEFgG<`|(Sf(Lb*V-!Oif&V#pR)Wc*61~ben3ND>6TLWWmC<*Irx0lhV;0 z4#9oXB_dagXrj(cRqY}l~A#wrcp{O}L|P==?@D6pl#ln@G02t0a9 zhl17fd3P+j-jB&qVKoyL;|9SIeP7L^@McZqz2wC&nNH5o2!$!=>6pZ`^Dts#lJQr= zBA9BJ#96PRhiWQgel!BYW%%On{@uSDK{>7-VKCb3RoxK*Ht|o98nS!r$&VewOlka$ zqjV+}%_C6iOG`^tH^xNwUOnM(Vm>ErPN)NXyrlc)tmL7H(5yWc6S~iT{`1Qa8GbXF z$`A;Qy837|y4vC?Szij(d)v72m<)-XQ*(1x;GuVU+o=@z8knJyAN;`|tX=_}(5?j@ z9uEAJ9(xW`+E$~@{M7?J)%iQV<2z~?t|80kYpR?i{3EAmY31Wj{P>TT=e#0o zd_LWDZDt(*w`-pg-_|4-~$<_cPBpGs8QPp%kPIy()7jKH_Jt z?%N4ytS;pBCw}55YKX|YQRt2iWR-(S@V;X`H+l1n-wc zSB=kO!tSNg=o~>k1kdqS8AfW%6_MxHzV>y?X`};F{?A-<&Ghcf zTU7{-WU+c{+G}7ei`Ym}zsfjRIQWx;dNvew`A;<5RNcB zXT;L2wX9eppr9EdTl2J1mZlGR5n%C{0ahBq{dfM(->JC<3be{Yu+a17uiadp!{@WY zgs>-Sy5fo}Gi>$j63R0(R{Gl4zIOVHzxa#kt?Ak>2CxX3Lu0mr&zg8+xp-wl`Ewa6 zfIq>ZOxhqc!w9BTV?74Tv!Wo>jlg_Snc1*Y3 z{`Hzu(|9!yA>6O?w=14qFK6^~potz4rQ|>}Ln=S{lRsI#p;7RVIXw9v|Kop5Z+OES zYG_!m^2dJc$BJJR+KO!FJ1$WS7SCArk9S_arsU*dco;hTYT1_tUc7xCb@68AF&RPA zHgJtopVb3TI4{QhDasCvtdRuDiv#5uJmu-|o+zNVWswA>stoN9JiS#x8-^3yzTE%@ zS%L?87jI`&821lmRT<-sZtDE9tnxF5Oa#p19(!DtN}qO04Owy`^@z|-@BXT*uBtj} z3(9FeYcGt5o{K{{OG`_|J2Yd67%ns?cj)C+hu{9~->%-DI_v4cMOx{slH?pP;P7O` z(75T^a`k6__Gi<7|L_03%7hR367YayZV`_8M({Un8jgWHo{&|Y(#zL|NEsnd&373dKKtx*^K9mO)S)4Md`1gxUTECM9)XYC7RaaU)nP@# z_J49<%9ZDHPpBgf2BM!of^$kEXp}LpWGFER4+V>X3<4rk-UN^_S`1AX=f3v5E8S;G zPa`KB4#HwCL>|PxA?w<&`Rp~*XJaTn|GC)+<(Wyzv(G-Ki~+?!kO?AT)qoiQf#>m} zjIFDSdOVml@fA=sq%!V*TgtI)a(6yvcG_vDmO&w)9l)aS7$1hnB|;Xmj+zQQovmY^zn$ISrlNjWDGSto?g=# zY{vGQ7@*Hy^O-Vk8m)JsG$b@+(-YHo?8+<}r^3we8@)={i#M8Ax^WOr5R)+Yce#&NCC_VhdpXRgj z91NfXUYsYm8BQ+Y2<^ckBYFVxw%o0S%frPfgN!fY0Up^PE7~eq!~;E{<_Wlk$02bR za+L5U4o(b-x@-4nY6woy<57R@<||+MO6ivmWvEwAM>{su=3rpSJI9K_W3c2Q7Y+gK zE$xOIS}3E-sRXNj$O}0!gvq%^H~6ck{P^+JYrmRRXtyWL+o~Qwc&;owhYyFAK~on7 z34gSq<{@VXPIL=i%HIK9eT4MmAOA$^|JA(Q|I7WT&SVPT(LGiv!-UZW6v7EK8Yy=4Bg}+89Sc{Y`vw4&MCcx5VfU z&up>WN9($I(eN0IKlzhCDWyn(H+}oLGyL=@|M@@v=VesT@P~frhiZOhv3DRHnfcfM z`d^n*MVYBHUg04{!4Odzctv4~)9W_;grAf&BP5LgU;JUzw2`#}9)0ikes2wNab6bd zNPgd!)pd-lwz23G!HrDfmsb}kRnI9oLpUAqm&2req7OVB`^5VZBh<2#D5N9wewj&NQVxLPOSnA zu4D%e4hGd3?YjMvMfs$cukmfn7-?m|e|5lDPSCP*GwZR{>Hc@#FBqXmr`XV|h-iH} z0-4|&%-9g3-B~M3jH&V#5o9qSY=>sT>U;5+$pBrJoeOl2c~A_5XNIoKqrC5Z@6DwC zhf0b2L^|W?)Q7-R3TKJ&4*UqT`0*~!pflm4{JRI# z!v)F(hqs3QXv9OLub(1(u*8Gq&dJc+Y6tL0RDF<^9%g{Z{p!I2!nY-j;sj zvxPX6D!!p0BOo7PF`$<3zT)Ck&1<)Kxz1#-VHhZ7i_y zt_T@1O2HFHb;3#K9kpyWO;-XTI{Ln{SE?el+s>uIZaT zMIKz#3q0+Ua#kPZTeU{s7+^FYTa2f21T@8SL$7*0%0nA`H9FIQvWL&s7;3bEUkBxD zqYOERPr2aJNpShwdC{Ega7?t}p1Xmgc7fN;=kEQ0wb=XVvd|a*$q`v`uWdWf032~m z`+lx0X}aFv!5a*)l91^wbL{^GJwfdM9lHC&2;H_%2*xl2*(#%T#LMtP&2 z;>1ia_6zeZym%^@OR?xpY4nTCCq#@8L0b&cNXrYO5ITTGfe>IGyP*6QTr^{Vc!H%| zqNAHWmZNUTyFd&j_~JDf4H0b|>i6e={^zA!TzjTbT8YJLZrsH)5?+Y=nSc6E2MvP9 zzJ2DzMq|+PWW@d`Mu@k1*=5gNR;H8$PfcS#B`deCxcrKuk^0EzZGO8*+!%TI!h!ozlrms zZiEnAg^kBrT1**r_mROMj8|n2hVU^2m_%7=2rYaFu}G*E0&xyRCOC%EFhw97CO6;m zmbX;nuE_jI4{pPAZODih)vH>hB_Mhw1f2I{u48FwsThmN@)6R;MIJ)zJrR4~ot!1M zXFl=FN{0pxfq+po?Gbf6c!te*wHjduH2b4J`lFh7?6}3V{1gb95;XVS3*4C{dQTJ@m^D|WN-4t|;EagPCK*CICRoOfZs>z9 zOQ9WliZk4#K`SSeVI!;8fM1*jdEn8!f zJ|l+Lg_ooCjK z>|g;da3HVn#LIRv!Gsq+f+;YX>b0n+JVOWg z(vzLGGW;L#vtWeg+C2(LAuw-)M@2v=AMYM$6by%<1l?Ud1dPH^#F6h{L0Vm0LF41O zP~w=>OlA0#DNdP~=Dow|)TOO?=jDX4zDP7 zTyTCV3wu6!Ar!nm2nf6huX6|G5fTE+*ntBkVWbQU@905DC-k{-RX2^P8i*ueU8Tvj zvvlxeXq3%6b|!?~m|O9KuP*q(pvWu8%Ny1x@om$lbn!KU1iMYt_CulBNqI5yCE1nY znQ4HBA3pZcLVpcY{TLzmf{zCscXkMxV{5(TLUZV75Noe{uJsRhRy?9=v zUB{yx1!Kg4(Py0v~xxo zsoUaW2egADxxqI|v3uIeXeEO#(lBU-p!A;6i;)APY1PV0FSO!vCeyuYlk!$4#z&Bb ztT;Cf8-M4u;ufE~Mi2aFbSpj4T2M0$+gUxdZ**r&Kl7RNd>D`z%#>F7H3tSn+qKNU zgZgSOj1{@nmX(Po%56OGoe{^2ZaU8o-z zcqop{;w>IqjL`;RQTD+@TWz$B0vy3{2yk+U2cwM;{&C}^^NcLGZdxiw+LjNnlm$0s zId|xMeg8Lgo=s~PKNQfoLySR?e)>qygqvr=C=d+H!WcURA9dtWwV9}0hJ8x~a~+t6 zkgJ1u%zD$C-ZcHYfA{Z-pag@`LhR0ipp+OKGzm1GDy}K6bjRs>{E&YJk)`#QCtH4Y>UA|Pc#sm@c@nRUVaM)sz;h;(mPY&DPw4* zso_O3*F84@rZrj0d27BfWeRZZL!Is7VN?JvWKUl0Re-0XubrEgeXfTO@k3V7NWJ7K z`CMq?E#Gj`ZpjP1p+~eguRo0KV&JV1_)MX%9qKa-nU{JS4{e7bLNiXCa`6IB@P>?O ztMG7*AL8Y2xwtd?^nEHXaDqYZwJ+CjM1La-WRRhUuLUNC^VN?|Q5Ic8uEC|F@LoB} zkf(!tvL#*Pp&Uo^N4!HEW77t;>kJ0GR?BGT@3Nff68N_cX&9cl2J3G!EcApPJv0zT z#r1~FKM-=eSQ8BUw)qxDL~>baK2*tIF=~{jAtjUb?!hE@8a+Z{5`n-l-D=Drj2f>r zgoN;Fm@N>9->`XKlpN(r;Wl%@cBqf%#+_Z;K|up9&*PAI9vR-?wYAV{&?c>~&Ty6? z9!5a9$^_4K3z#@Cw?z?A0+bWHq+1>2(>U6b>*sgfeOGxp>PdOQOCtcM4GM1&Y{Cd1 zb!8+O3fJvL!3V8u<|rN>Xo!{?SvwUcCynwV%7q3m4Nuh9k zw=xzRqI?t+T-1f4vH-vkhXCFp%!*v~<9P@5RE~0a(`eYwDL>8v_~dpm@F3NTQfOts zxPMo60T00l&(~HyoyS-~8j70MujomW}XPfXP803>)I{0;6;48m+P}Uk)(|Jn!Mi1UB zMb^TtaiF_6@EmYgXU0K!wxZGK<<+=&+Z+U&a-R0RV^Vt&57$kXDnIu%#4^(pElucK zF?V$gu(Bu*L6eYYZw|O==tYCn-@F#M1vBZyyH;1q+&qX0c|4-Dn|6!om9bXnH0o(? z#}L`pty}jii(#`P0@#Z|UJYKo@VXTRe0bMr3YS(wU6!-@EQc5lE6+Fr-X;0$ptuMr2`m@n#DWtA_H(nL(iJe=g8#FMb7v~_~tAm&Ce<1rcat^?U-=Yy}-q16vjS%{ZE1fh0{^_6o>FMwP{lC9o zG0Lzrw|3gj)P4!pxX}*1xJ}jt4$5D%5gG!$g3Idrl_#sOx-noFAu?VKS>x0U5s!xw zB7hnM26f|J4GU3K78A^E7;@m5QJ$2WhRcJalra|^p#{Q*GS3YfMd(E?fCc zZ|`UD*#7f>{?GN!i4}qxT=6739yZ?cD8F%W=H+P!cV_85d`xolm?=AaYQ+d&ixBW0 zPKz*#PccIG=Vf2A;!r2$wc;T3$^uXQJ!=?^m%4Ra!3?g8_)4c*VaI*ak@0Z-7pQFoac$rR4dDBZlm$k22sP zAA_cisfQk<_NU%@EpTjEp?u+$R=To6XX#cwNJ8-p5g?wGvY!n8V9h!T~zE{ z9{p5pAUvis;06|F18lS+)6#&g9(dfeu0r#pZT!fO{7AK1bzTf$pc@&Wqa3c4y~ua< zZk^FO^&kDCe^kbE5#HjpVQEtxWc%TQm4|JB9xm;-^88_XLXX_=tW{_;(YQ6wzz_lJ zPT9I9R6GGfguxiw%xU6cpayz%6ai0FHy5EbSj=FZ39`n7@ZdBI9y&qY^T6076fAkR zU1tq{1m;tptj6%wuYS3NP94A|K)UA|;aO)rsf5+nL+`q4<%Ls5kI`ttBMWh^EWet5Po*kvZLu8Sdaxs-x>gTrW|kM1=AwtQPTo-@#B zf;JS5YmM4HWvo}AF;Y+hJSZ=Q5v-;q0VnjzgNJ}tc;m~c8sF9Lxw>da=`IEh9z8Ui zZqVR@DGm)aQcA+1j>?dh(8Ej-c z`p%Emj4Zy8337{;aOm{TXw%9Itr#Fm6MqbUa1uB<=+>|c!ThKjLk%WHrA>4|5BTCc zTsa)%4~^7iH7v@`u(e)=UJlynZSl-4P=TxAWNk@%BqI!~a@7wGWJDd&%QM4^?!jvQ zH+}~@Z_j%@AN=5l(kpvhy^Lz#Lb3pV?N^tL)pe3 zJsBag0$1`{p9f#)`Jf9tTbA78hqjH+=wT>|5pRC02VC@u(G3s42ggAU(Zw}7Xz%z9 zF8ScZpfR3{>p&LZx){iw&}ADn>A1youGIlNZHN2lp8x4i7SQeN<$*z)xBd`>WVNeDhof#HJpU3H1?+9%u zL&}OLh{n8DjR_4Ib%qsAaKImmQd&w59uD~kKEbA7(OBBW09S9L^0cOK3gy$dW z?!SL$IVk_}KmNyR8(+`o2N+QGRR<0bd3t9)8?kxw_=LToHjWheg9~0M7cOLlJdrg< z8Lcb;*}Al~=7Q82-jp?3>eWcw@}qr%qfCd;xT_0ix$CHRqOIT^y2A@yz-Fk(3>kJb zkCmy6mO_I@1Og*pR3(cD)FixI^^;cKLK6 zka>zrOG{OTYjr}KR(uo|0Y@u_7A+}QdElf>4uZyJ7zi!9K@55h+?3Zi_ZdD6ltX^F zGeYokuhDBf%5W@(uJdA?>n_uChkK##>n1;|(@{PeGp|};geWP!6pD5+eI;1MSUS@+O1$Pw}G>9Po&o`7B5q(5^?9cd)ba9(drvava{4Z|m&H zXQA)8XYfFM1hPt=npR+6cipvxKjXq_f}iyF-g{5+08V(R{h*aJTbE*lq6e(_b8bDO zj>Bao%VG8(3{p){ZB5WJ-SkN@#ME?J^$yQkwB9fjxJZsEhBvY10yOj{8P zKSoLP0tNWP{m~3s?}`R_G$B6>tkq0fyeE(jOcLJ$M1!FClptnb$;o=0DIrQD99W^Y2>W^-E!l9J_?!tg&$>TG?=U`OeWYum+x9V8-HhM zz1!f0QF#RE;qUn(&BSTQ%Fwu)UedMK4o1V5UOESusbU51ZJ4|9X^KueKicmkPv>pA zH*VrrE7#Qudp}^gk+;KQxgFp2Y2_lVXAbE*PoF7VhkC+~QfV9((|4I&PQz86ypAr% zGji6vaNp&*ZX8`Vo~xgujkuOQX@ySb>;S8AT6{KAk6-akYdAGb`Q&dLr0zO2UGS&V z$R{m1X&QAoi!eIwz%!W~vQ+IT^4c(!+xW}pe!~W`V+d{xt*_8{K!(ST9Xpp{h*eLD zvFouKcX%pOSzV^~*XK^_%sFi% zWD`<8qsFN!QxjlM!IH_XPuwGxTXNw%1bLv3nL*~ z4E0^~ELa$2X!I)rB(9H?7}yI6H`>^{4jVG|ymxPgjPgtv@->94aa1;;)$1Tkm}Q(> zFN5InN_d{e$Tcj7JUlPm>+Y=>-r*TF+=26`jZZ|l*O)wasB2%F?{V-NdFceLhai+C zZ_~#8sLQ&-K~KnB!Oii=zL4R*5mLwe+mv>FzDQZL2^|CtLC=7f%JT%b>DXuW#v@)` z<0!8NZ(fY@(~ub9Rt%oQjey7Hskv}{WhdvBVr;{Je@m0M&R}ZvX3$Mz!@MC!G^sKT}A3Qxgy%a|~L};Wu zPJo`)?YDnDcntpRN?F<|+0cIUa6E+5-o0a|f-VZ~Z6IAcI&|If4&RoRmWpp=Lg=*J z^T#js)8oZsylR-*sL*XiJouf)^1#Gb)av$ z?2c>sb#DlMbx;?(w{&29)=JmU|5wj{V@7B-!ix;W1V<|(*Uhv=0RRJ`Fxt`iq?L{b z<|~Ygq0)F3BSfK6q#ZhcpC#a#`G!!v97r~TO9@@Y1Ar|A; zhCRTMw(HpN`V0rg2hKLx{K!W?5@UH|dO$vfJ`WKVZDWKUOe4#myc)PJy*4W-|(3is+VgLp3-A9TTZ2S z?GWTeFYyj#H$2zUktwkIUfmmB0hxc`>HyEtq3hupuNOT%XC%o5xQpe=N9m9SWsyT^ z(Gh>~7EWDWm(%AHPdq6ybV<@2T0?(Zwj38e=IgC7Xm|}aIGn7#Z?OVw7`RZQzDit% zBYZ#ayf|gaNB+L}1s{vMx2~0=Y{rbdYb$LiJX2rvK~KC>XYb0G2Q@t9c?U92wv?%! zWQ)NCzxe=G=jn6P3>{sgNz=V~+_-dEYn_|!Ydw3YIC~o6qq-Y!6PQvEA`R;49US@vEQ=d}rh*)^xeS|ie z=*OUb-}ilA8Fe%f)XPEx3PWHZ&O86S`e%8gbJW zOxF(S7$10Cam5uiM4^7@)^g+Qu-w(5H%1XK<_w`NUl<~MY-NFWoo^A2vV|_+S=nAm zP=5xH=gYV?tcJrOP&S#;`xW0ouV(Akt+hIie3<|7-V%oh4U{8v92@mXO(EkG>Uc<@$l;8{CGaH71)i29n;Msr5$#V>kE$%w|mIn(Yq81@=GBt6sh8BIu4i$+~<=T_K; zm3Qp4{CK<`A?*{kKB3-Qd*-G2oJtIwp}p~)GE3Lj75&Kp;{iuQQVcEwf;WpjA~M4$ zdy$>2TA}Hl{HTlPUhYK?q3P{L_G!8G7@)AFgcTHMJwgOWI<)e{VDMMLN zyqmY^CG~L!ur7<{K5K60b?Lv z4@EH|_BAse4c0PUS+E=yIP459h9doDu6Ne9P86N;y4Ui$^spG0#$7`%}lK z43#f|qJ>_{)#(*599H%9>jmVDkyH=zfOd?tItlPL8I9g#YH4Yy;{Bk%IQ)e}<81iz z@XdCK9*qTijYKR5mtlkS>f<2u+5!GC7&qQ9K4EV&T!!VM3ooiVsyjn0kD>8)R`e{j zCB{}yi7axyq_ev@hf8^A?|^&r1TFvG-}`&@Zk#sAaX?S$;DeU<()C-e$Eu5md%i09 z|Mpu3wgbmyb)cs@ET;X1U-*UMb3enYfAeqtP2FlU9ne!eKG@0Te>MF7M(Cj^H#eS6 zqHz&aLrK2Owqe8iC5v>%cUqNi4M|(!*k`WyYB|nu%zYbKkM1gDn-}v z6o9H!vfD2OhX!a`4t9X)pCBZxkcZevPy zf(v?qr6+_&0$NfqhA7e2Gs9gJD}~A^Htv0Gck z8mmiK;L;A8no?V0F_9L8rl9BZyz`wtT;BJcdE3rV<(|o%d*6GXALpFsobNf$bMJd! z4>C9opV{MI8+1qq+A?c&PY;jUkVF7)ypk)xZ#*Og_`omz&s0DM!f8Lc8}9K6Ab~CW zz&8Sx`nE(yugbVC0Rgi5lkwAyBmghS_&cvWB8yEwz?cq=r%lkb)EdIS`T~RU#=>mt z{`~Gq{#$F~ z_@AXKCF}bi)K6Z2F!>QcuPL$=hd2IXEbwCt=p=79k8WK9!Zzc`M(F8O1!-ePZfzho zC$MiO2t_Zq>OTH~KVvy0x(ivc2)UQqQ=W$F&pBo{Pd)Wiv%fJ24Yjj{pUa*LOxCi% z3Pj$n`6_B*p6`N2}9qvvcz}w%H+E>GBmu(aDfBR2mx?9_5BEK zdcosL1z(_o$kFrdGrcY^Pwv0bt+7y7;J>SuQ@sKG@O_8djLvT;2~>^GwYIdOJmAKU zzzm4*u8bWJ+nWKIsklyFH?=J(Dof`a79WBMpft+^cJnB@)23izb`z3)nic!53Nm&H zsB9wR={^#>LC#sW6(sRO4+5c$J<+!rx5R=>y&lykm$3o(A(?(OFn%dJgY0y*A5v0&wZ6qr%&bLw1SQ0GP0Zb(U)`f zRcJDk?81Yt{Y_{g~7k<8@9Bc0Mi#*7_#D8bAE z@UV@Q3h4c8Qm|yp&d~!qw9z+S-h1y-n|ZwX=3g418*hC5vR;^Z_&fKuzTUaO9{*bU zI=4Q0CI{8@?c8v!?#26yu zPY&|i(uZ<>LMG$mGaV>n9Qc~qkn?oLZ?+qVn*i7Ok6+Te2W5KlaFCe_;tTFmdUFYK z-_XoC^zzFu=dhLQ6TkHfb>M-gylB@rdst|rWU8+}?RX4A)3h?@T+JEki8-0EZ#(a( zM@CQA54?S)o?NPBu)Av6rIxLLyFd_QmYK#W7&+jOkpdPVg@C4dz}stplwkg{D5En4WqW@f12Es4))t7$ln=XoH043nj z9{@(c+0vac$i12b7Qt5_qJM1)0zge&flNCIe)^b2^bTanXL*gyAa+GoAmAKbnFaOh z_3E0Hc)g4OuHTgkFvi|Ek&!J*dMv4FC$>Q^^vTZX%mWaTA^o^UCc33ZvI%4!8ek9F z@%vI9H1M-6=)yY}+Jhly&t7|N5M2ps#?Xs9wOcG#n|{{(pOujPs|E5u{aMoS#|oyF z6V2GGP^m2T#wO|2XZ#v>_D6o?8vO}C?G5o2*lK~bE1Tee-*GwSb&w&8& zshTOsZW$L4laT`r*^g{jJ!NzA7Qg{>j)-EMjx#QM_kN>gQ% zn(C8903{bnJJq<=87KVLSp%~-D=6Ms0pgwt7P|{Dv=O-!^8}%vKLCnAh0XylFryFh zcn6#%PyrASk=-nhuk5T1gY0P{gB|%yQYM zr9d{IPh%sHT2j*vUH13&=u;ap`t!Ro^hjsOa0Z0^ zYFx;}cIZsfL1y*#1e5|1=aQvmRw292{S2UIMgknQp-+zEU131O!wZ}dI0I=j z2u=n(WZ@5d|ABT-h4TV9K*m}1uMTiRfQRuSPszz7W1Ju-2(bgY&==eDPzJjhlI2~p0$D*yU@)c#2v0 zr>l@L(5G>tQ{$Gv?~(pT9$9I!8+(ZmJ6U~ewSm4i=mSrdfR`&6`K&+sG>#HAc1%_> zeu@}O5uWJSm}Ca3EE{%DOS`VKYh!4yA7qRZgp8XcjK4`R&;R{=)35RQOy8~c_WbMn zh5@t4?>u?ZPkAqM9+H&UrsT+-&`6<^FGj&@^Fh<~jFS zthWM(Y;jcU{stVlGW?vE)d?U552z^@$B>b6?tBT<`H!#G7y17EL38q#UV5p`ZnR|< zVCjV;r)~Ejj=y?*>Gd~WZ=lUsv?04>fXE}P>UizFfWk?EkM@#{0*-udi8D9nY_+fb z(>8!G-8Xd?*vvKnCOKReoPbJ#5MIbV&2W_$Xw1w279Ih(vNCcRcfR<#QcFr+N1sev z8JXVEqemNH;!{4${kF+Z+~0Qln;~D1c>3w5*X?&&9SI)XF}4yaHY@NL-$jX^ z*={C{L1+POatOo;I2gwPYzDQbI5HzvPF4lH%x2uo=3wjDS5=I$106Gn3+FE^`FRG$ zBa>7QV8}N0&B-h=a4gpaH(={&EVB=Q8V43!l;xcGRNpyIg$W!25TMaF!mq#rJODp{ z6EKlk3H~jK$)eMrw*%0FHUOVCYygmK;U$0)d0V6PFQ4%RyaE`&LLkEr`Lrz<07T$L z?snt4^=XLz_3_xxZpWb7qCw;GK>Xu%O-@C=%R$=o;rr$Zbo01PN(8UmFp z7;tkkdrrb(vW(EPzybXD`QV&N7E~LeA+^yU}BQew$8E^rGxWq%9yx zUf^nc@WBQIR!b=l)w|i0^F17G0~+@w&7AJ8B|0-8vvz?SUspb=@mZT)The12mVe2i z9piWPFLttOU)LPPv6e-LpSJ=@ins)5RqVLtWv(69RF>p z2F4(?fO;7>=duSz0*)*>OGALt(veInOArBN*{_TdkeO-&Lk@!&yfzUq1PaQ@rp-n; z2Io^oS@k#^&~OZ-03t_H-v(&$W`+Wc?Bk%?019LQJ^>)JFn|Ie@GS^<%1$<~j&o*o z0(nq zzF-=gaGl^?Cs(|F196I!OT-v0y5sjuqfI(M+QJ9h zbDd7I+-SBNt1wqv&fi)6`tSsUW7>gqds)0g)Y(vx$N zMEhJ%+v9%gG%yCC1$7(X0NA;a&FMIr=Q=G4K)adgtfJKplU;SeBS<5}3%2$;R<*oL=VG zJ7#o%ck-x@Cj_uoPp__LmhI%6f9eSs?k{*~VAt+lO&8=d>oO}#mZ}+g66n;UD?sab zxiVvcgZ#iO0XSd+Q~@ygvdk&a10_19OJkxQ`7(BNaHcYTNrzdDB`nv~0k{A^^&;S!0FI1V!T|xRDEwf{s8cAh?&IZMrb-bYVl< zVxvHo9NKkF;LR*nKc`nux9?&_=lXM=OxjF9(Wdk4gZ%U+8KM`m;E8PXq3;mB5gQXI z=tvSlK6Yzn%`OEm6x}+9XFfwtjRXqMmLm~9*p6|^nBbWY8E3j9 zAH7Z+kJiZe@1|>D3_{nbQW-eV>h~*NFtPS@R1P=ss0E1uy#I5~Xb^;pe+XM%nIlg|h!GUFdma$w*VAG~+GW{&C zIHzuaBXZ=N&$ia~CpD8Rd@*Y}aq`5c+RzRf)>lu!pi7`)7D7L=(=0JMreA%k4~*!6 z-T|J>{NRCu4Ons$n(Xu&zV%~F1d`{Td#)|*X;Tt`U;PR~t$c}5i%+dDWq`ad_`UGL z3k?J(l1!F<=$($01FCohgl0)(a$Ry@Ea}-ereDico?^75+k7@n zs{*AD!R)Qox7wIm!qwKw%1Q%Xwh_GnR|x{U@fg2=D*(}B+BNQ$&XfVXW!)k z<|&ImV?}Rd1MGqhJ*y*$NHUXg*G~AC3|Y!EW1}Mhg`8|&Kr&`XUB~JsK=2>I3NJ|( zlri%WU?m!Y5nD;ZqMXfmu?>6oGR?pRD!g04FxIEm9^?t%jgj%+mT6!NLJO!i4iqN? zIGm1ya6-onKMs_=F5(300wd*Qi@?D02OMgVPgM^+oT$tPhDfPobq3PK17 z0y;WTkG_DhjM~ys#tNbb zwO8wNDB!~Bl|d=z*tu+gh4TZTfD<6{+c4TN8}bOUnT_R%w5J`PfhTYVOtNjxDhLe; zFC3F|0dCGIO9UXC3xAel04{z615U_6Lw(;l*Y8~i0G4pPcoZN20s*p@zdu$#dQu5nf=Bk621ycj1uO9qUahbES5 z*^%uVAAv_ewyF@G)s@hA)suJPnF&g61nBUR_Q^qS5=ms7$Ukp|}Oz@^Jn=wQBN&U>=jH7Xql%%}Gz}T`2dms#0=?TAP0A?;WOLD!v z^t?GHm-Z}IEf?sLnH)e}kTtHrS-J2g$e95NSnTJ+k3MWkkHm#e$U!E2SyEP3Fqf>D znYfO^mv%j>o?tC;p`SCg{7kpezw(yWEZgCe9=(%HVk3xzw1?kp?1p{E=FNnRvGb9M zeX?Cij=&;_)2C%hLDV=4E_g~E{LmX-=z`wVXAA1&5qx84>;zW4(rI{%4#NAmzxf&% zgU|vxjiYl8#|(7nu$pr%#F(==7o(1&I2UJhtUZ~ca)9p8J%<{A9XNQPIW?yjEP!6h z0nWa?v^hNIbNX^j4%xrHIHj?m6Sp?v^Pb0g>UjQzB z^?UuL&z$#JJrrF#PM>}G{=9xNmd+>eIPUxLSvhShllD@s=hwLqpab~i69}?wlo>+G z4fo;O`M$55AM&k?YZ*(&J^#wn51SeCpT5&iufJT&K4t8+iPD}~mE}l5F3Yt(oPi_D3Iz*JWlbE2+4svD>W0#OKsg)0Q?6{i9xw?L_@cz0}EGKX{ehn`x0rR&O>W@S7o|ZrbYi>Zh&9qP_5+vaZ?a z1nI|dK0Bw5GVCTnC~exiu6%#2UTD~-V52Sa;31p`6zn0_8lu6lH`^Xs{wQ0*|*TbXzu+Lo6 z{_uEO`DuJ8*Vj#%@R84bx#2Zs@M>&ADR0IjdB|sFruCP4)Aq{iGyP_tHtqGF^V&$A zzRa{B*7v7uPiZgv{#xIz>nP*txYvcx8&ThPjd_D_4?gfqX z`DtLB2`!-e814d9TG2S?qV;B#4!#?tPUVACi?}z1Q^*QVOytX#FHf$3w!*hKb^R5l$*i60asiWOt zy`JxRJoY?|$6KR;aVE4idfk>*Z`64 Date: Mon, 1 Jun 2020 17:57:35 +0100 Subject: [PATCH 38/48] Reverting because it worked! --- apps/BLEcontroller/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index ad2d5aad2..3f9dfa6b8 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -4,7 +4,7 @@ A highly customisable state machine driven user interface that will communicate Amaze your friends by controlling your robot, your house or any other BLE device from your watch! -[![Video of watch and robot](./video.png)](https://www.youtube.com/embed/acQxcoFe0W0 "Control your robot from your Watch") + To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: * message number (3 characters) From 93f818eef492ac1d8da1cf1c32ed6f835fa4feb2 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 18:11:18 +0100 Subject: [PATCH 39/48] Documenting message size --- apps/BLEcontroller/Bangle.code-workspace | 7 +++++++ apps/BLEcontroller/README.md | 8 ++++---- apps/BLEcontroller/app-ex2.js | 2 +- apps/BLEcontroller/app-joy.js | 2 +- apps/BLEcontroller/app.js | 2 +- 5 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 apps/BLEcontroller/Bangle.code-workspace diff --git a/apps/BLEcontroller/Bangle.code-workspace b/apps/BLEcontroller/Bangle.code-workspace new file mode 100644 index 000000000..90587e88f --- /dev/null +++ b/apps/BLEcontroller/Bangle.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": "/Users/hopkira/Documents/BangleApps" + } + ] +} \ No newline at end of file diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 3f9dfa6b8..c02e29543 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -7,10 +7,10 @@ Amaze your friends by controlling your robot, your house or any other BLE device To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: -* message number (3 characters) -* screen name (3 characters) -* object name (3 characters) -* value/status (3 characters) +* message number (up to the least significant four digits) +* screen name (up to four characters) +* object name (up to four characters) +* value/status (up to four characters) The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. diff --git a/apps/BLEcontroller/app-ex2.js b/apps/BLEcontroller/app-ex2.js index a24d7805b..4ed3a5eeb 100644 --- a/apps/BLEcontroller/app-ex2.js +++ b/apps/BLEcontroller/app-ex2.js @@ -45,7 +45,7 @@ const transmit = (state,object,status) => { n: msgNum.toString().slice(-4), s: state.substr(0,4), o: object.substr(0,4), - v: status.substr(0.4), + v: status.substr(0,4), }; message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; NRF.setAdvertising({},{ diff --git a/apps/BLEcontroller/app-joy.js b/apps/BLEcontroller/app-joy.js index 66bad3934..8da1aadcb 100644 --- a/apps/BLEcontroller/app-joy.js +++ b/apps/BLEcontroller/app-joy.js @@ -45,7 +45,7 @@ const transmit = (state,object,status) => { n: msgNum.toString().slice(-4), s: state.substr(0,4), o: object.substr(0,4), - v: status.substr(0.4), + v: status.substr(0,4), }; message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; NRF.setAdvertising({},{ diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index ba172b047..c8217988c 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -46,7 +46,7 @@ const transmit = (state,object,status) => { n: msgNum.toString().slice(-4), s: state.substr(0,4), o: object.substr(0,4), - v: status.substr(0.4), + v: status.substr(0,4), }; message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; NRF.setAdvertising({},{ From 5c2bf298502a2652874f982098c6de7c73dd31dd Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 18:42:35 +0100 Subject: [PATCH 40/48] Switching to Dalek app --- apps/BLEcontroller/app.js | 255 ++++++++++++------ .../{app-ex2.js => app.js.old.js} | 255 ++++++------------ 2 files changed, 255 insertions(+), 255 deletions(-) rename apps/BLEcontroller/{app-ex2.js => app.js.old.js} (65%) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index c8217988c..4ed3a5eeb 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -19,19 +19,18 @@ bottom_btn = false; msgNum = 0; // message number -NRF.setConnectionInterval(100); -Bangle.loadWidgets(); -Bangle.drawWidgets(); /* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_printer = {value: false}; -var status_tv = {value: false}; -var status_light_hall = {value: false}; -var status_light_study = {value: false}; +var status_spk = {value: true}; +var status_face = {value: true}; +var status_iris_light = {value: false}; +var status_iris = {value: false}; +var status_hover = {value: false}; +var status_dome = {value: false}; /* trsnsmit message where @@ -71,16 +70,52 @@ with a unique name and the data from the Image Object */ const icons = [ { - name: "switch", - data: "gEBAP4B/AP4B/AP4B/AMgA3HPJdlVvI7/Hf47/Hf47/Hf47/Hf47/Hf4AvIPKRXAP4B/AP4B/AP4B/AJgA==" + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "spk_on", + data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" + }, + { + name: "spk_off", + data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" + }, + { + name: "facerecog", + data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "happy", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" + }, + { + name: "sad", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" + }, + { + name: "hover", + data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" }, { name: "light", data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" }, { - name: "back", - data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + name: "speak", + data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" + }, + { + name: "dalek", + data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" } ]; @@ -110,61 +145,78 @@ the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var lightBtn = { +var happyBtn = { primary_colour: 0x653E, - primary_text: 'Lights', - primary_icon: 'light', + primary_text: 'Speak', + primary_icon: 'happy', }; -var socketsBtn = { +var sadBtn = { primary_colour: 0x33F9, - primary_text: 'Sockets', - primary_icon: 'switch', + primary_text: 'Speak', + primary_icon: 'sad', }; -var lightHallBtn = { +var speakBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'speak', + }; + +var faceBtn = { primary_colour: 0xE9C7, - primary_text: 'Hall Off', + primary_text: 'Off', + primary_icon: 'facerecog', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'facerecog', + value: status_face + }; + +var irisLightBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', primary_icon: 'light', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Hall On', + secondary_text: 'On', secondary_icon : 'light', - value: status_light_hall + value: status_iris_light }; -var lightStudyBtn = { +var irisBtn = { primary_colour: 0xE9C7, - primary_text: 'Study Off', - primary_icon: 'light', + primary_text: 'Closed', + primary_icon: 'sleep', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Study On', - secondary_icon : 'light', - value: status_light_study -}; - -var socketTVBtn = { - primary_colour: 0xE9C7, - primary_text: 'TV Off', - primary_icon: 'switch', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'TV On', - secondary_icon : 'switch', - value: status_tv + secondary_text: 'Open', + secondary_icon : 'awake', + value: status_iris }; -var socketPrinterBtn = { +var hoverBtn = { primary_colour: 0xE9C7, - primary_text: 'Printer Off', - primary_icon: 'switch', + primary_text: 'Off', + primary_icon: 'hover', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Printer On', - secondary_icon : 'switch', - value: status_printer -}; + secondary_text: 'On', + secondary_icon : 'hover', + value: status_hover + }; + + var domeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'dalek', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'dalek', + value: status_dome + }; /* CONFIGURATION AREA - SCREEN DEFINITIONS @@ -176,20 +228,30 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ -const homeScreen = { - left: lightBtn, - right: socketsBtn, -}; -const lightsScreen = { - left: lightHallBtn, - right: lightStudyBtn, +const menuScreen = { + left: faceBtn, + right: speakBtn, + btn1: "hover", + btn2: "light", btn3: "back" }; -const socketsScreen = { - left: socketTVBtn, - right: socketPrinterBtn, +const speakScreen = { + left: happyBtn, + right: sadBtn, + btn3: "back" +}; + +const irisScreen = { + left: irisBtn, + right: irisLightBtn, + btn3: "back" +}; + +const lightsScreen = { + left: hoverBtn, + right: domeBtn, btn3: "back" }; @@ -227,63 +289,78 @@ one, then the state machine will change to that new State and redrsw the screen appropriately. To add in additional capabilities for button presses, simply add an additional 'if' statement. -For toggle buttons, the value of the appropiate status object is +For toggle buttons, the value of the sppropiate status object is inversed and the new value transmitted. */ /* The Home State/Page is where the application beings */ + const Home = new State({ - state: "Home", - screen: homeScreen, + state: "DalekMenu", + screen: menuScreen, events: (event) => { if ((event.object == "right") && (event.status == "end")) { - return SocketsMenu; + return Speak; } if ((event.object == "left") && (event.status == "end")) { - return LightsMenu; + status_face.value = !status_face.value; + transmit(this.state, "face", onOff(status_face.value)); + return this; } transmit(this.state, event.object, event.status); return this; } }); -const LightsMenu = new State({ - state: "LightsMenu", +const Speak = new State({ + state: "Speak", + screen: speakScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Iris = new State({ + state: "Iris", + screen: irisScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_iris_light.value = !status_iris_light.value; + transmit(this.state, "iris_light", onOff(status_iris_light.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_iris.value = !status_iris.value; + transmit(this.state, "iris_servo", onOff(status_iris.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Lights = new State({ + state: "Lights", screen: lightsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; } if ((event.object == "right") && (event.status == "end")) { - status_light_study.value = !status_light_study.value; - transmit(this.state, "study", onOff(status_light_study.value)); + status_dome.value = !status_dome.value; + transmit(this.state, "dome", onOff(status_dome.value)); return this; } if ((event.object == "left") && (event.status == "end")) { - status_light_hall.value = !status_light_hall.value; - transmit(this.state, "hall", onOff(status_light_hall.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const SocketsMenu = new State({ - state: "SocketsMenu", - screen: socketsScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_printer.value = !status_printer.value; - transmit(this.state, "printer", onOff(status_printer.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_tv.value = !status_tv.value; - transmit(this.state, "tv", onOff(status_tv.value)); + status_hover.value = !status_hover.value; + transmit(this.state, "hover", onOff(status_hover.value)); return this; } transmit(this.state, event.object, event.status); @@ -344,7 +421,7 @@ const drawButton = (params,side) => { text = params.secondary_text; icon = drawIcon(params.secondary_icon); } - g.fillRect(0+x,28,119+x, 239); + g.fillRect(0+x,24,119+x, 239); g.setColor(0x000); g.setFont("Vector",15); g.setFontAlign(0,0.0); diff --git a/apps/BLEcontroller/app-ex2.js b/apps/BLEcontroller/app.js.old.js similarity index 65% rename from apps/BLEcontroller/app-ex2.js rename to apps/BLEcontroller/app.js.old.js index 4ed3a5eeb..c8217988c 100644 --- a/apps/BLEcontroller/app-ex2.js +++ b/apps/BLEcontroller/app.js.old.js @@ -19,18 +19,19 @@ bottom_btn = false; msgNum = 0; // message number +NRF.setConnectionInterval(100); +Bangle.loadWidgets(); +Bangle.drawWidgets(); /* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_spk = {value: true}; -var status_face = {value: true}; -var status_iris_light = {value: false}; -var status_iris = {value: false}; -var status_hover = {value: false}; -var status_dome = {value: false}; +var status_printer = {value: false}; +var status_tv = {value: false}; +var status_light_hall = {value: false}; +var status_light_study = {value: false}; /* trsnsmit message where @@ -70,52 +71,16 @@ with a unique name and the data from the Image Object */ const icons = [ { - name: "back", - data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" - }, - { - name: "spk_on", - data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" - }, - { - name: "spk_off", - data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" - }, - { - name: "facerecog", - data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" - }, - { - name: "sleep", - data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" - }, - { - name: "awake", - data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" - }, - { - name: "happy", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" - }, - { - name: "sad", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" - }, - { - name: "hover", - data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" + name: "switch", + data: "gEBAP4B/AP4B/AP4B/AMgA3HPJdlVvI7/Hf47/Hf47/Hf47/Hf47/Hf4AvIPKRXAP4B/AP4B/AP4B/AJgA==" }, { name: "light", data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" }, { - name: "speak", - data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" - }, - { - name: "dalek", - data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" } ]; @@ -145,78 +110,61 @@ the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var happyBtn = { +var lightBtn = { primary_colour: 0x653E, - primary_text: 'Speak', - primary_icon: 'happy', + primary_text: 'Lights', + primary_icon: 'light', }; -var sadBtn = { +var socketsBtn = { primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'sad', + primary_text: 'Sockets', + primary_icon: 'switch', }; -var speakBtn = { - primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'speak', - }; - -var faceBtn = { +var lightHallBtn = { primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'facerecog', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'facerecog', - value: status_face - }; - -var irisLightBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', + primary_text: 'Hall Off', primary_icon: 'light', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'On', + secondary_text: 'Hall On', secondary_icon : 'light', - value: status_iris_light + value: status_light_hall }; -var irisBtn = { +var lightStudyBtn = { primary_colour: 0xE9C7, - primary_text: 'Closed', - primary_icon: 'sleep', + primary_text: 'Study Off', + primary_icon: 'light', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Open', - secondary_icon : 'awake', - value: status_iris - }; + secondary_text: 'Study On', + secondary_icon : 'light', + value: status_light_study +}; -var hoverBtn = { +var socketTVBtn = { primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'hover', + primary_text: 'TV Off', + primary_icon: 'switch', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'hover', - value: status_hover + secondary_text: 'TV On', + secondary_icon : 'switch', + value: status_tv }; - var domeBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'dalek', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'dalek', - value: status_dome - }; +var socketPrinterBtn = { + primary_colour: 0xE9C7, + primary_text: 'Printer Off', + primary_icon: 'switch', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Printer On', + secondary_icon : 'switch', + value: status_printer +}; /* CONFIGURATION AREA - SCREEN DEFINITIONS @@ -228,30 +176,20 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ - -const menuScreen = { - left: faceBtn, - right: speakBtn, - btn1: "hover", - btn2: "light", - btn3: "back" -}; - -const speakScreen = { - left: happyBtn, - right: sadBtn, - btn3: "back" -}; - -const irisScreen = { - left: irisBtn, - right: irisLightBtn, - btn3: "back" +const homeScreen = { + left: lightBtn, + right: socketsBtn, }; const lightsScreen = { - left: hoverBtn, - right: domeBtn, + left: lightHallBtn, + right: lightStudyBtn, + btn3: "back" +}; + +const socketsScreen = { + left: socketTVBtn, + right: socketPrinterBtn, btn3: "back" }; @@ -289,78 +227,63 @@ one, then the state machine will change to that new State and redrsw the screen appropriately. To add in additional capabilities for button presses, simply add an additional 'if' statement. -For toggle buttons, the value of the sppropiate status object is +For toggle buttons, the value of the appropiate status object is inversed and the new value transmitted. */ /* The Home State/Page is where the application beings */ - const Home = new State({ - state: "DalekMenu", - screen: menuScreen, + state: "Home", + screen: homeScreen, events: (event) => { if ((event.object == "right") && (event.status == "end")) { - return Speak; + return SocketsMenu; } if ((event.object == "left") && (event.status == "end")) { - status_face.value = !status_face.value; - transmit(this.state, "face", onOff(status_face.value)); - return this; + return LightsMenu; } transmit(this.state, event.object, event.status); return this; } }); -const Speak = new State({ - state: "Speak", - screen: speakScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Iris = new State({ - state: "Iris", - screen: irisScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_iris_light.value = !status_iris_light.value; - transmit(this.state, "iris_light", onOff(status_iris_light.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_iris.value = !status_iris.value; - transmit(this.state, "iris_servo", onOff(status_iris.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Lights = new State({ - state: "Lights", +const LightsMenu = new State({ + state: "LightsMenu", screen: lightsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; } if ((event.object == "right") && (event.status == "end")) { - status_dome.value = !status_dome.value; - transmit(this.state, "dome", onOff(status_dome.value)); + status_light_study.value = !status_light_study.value; + transmit(this.state, "study", onOff(status_light_study.value)); return this; } if ((event.object == "left") && (event.status == "end")) { - status_hover.value = !status_hover.value; - transmit(this.state, "hover", onOff(status_hover.value)); + status_light_hall.value = !status_light_hall.value; + transmit(this.state, "hall", onOff(status_light_hall.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const SocketsMenu = new State({ + state: "SocketsMenu", + screen: socketsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_printer.value = !status_printer.value; + transmit(this.state, "printer", onOff(status_printer.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_tv.value = !status_tv.value; + transmit(this.state, "tv", onOff(status_tv.value)); return this; } transmit(this.state, event.object, event.status); @@ -421,7 +344,7 @@ const drawButton = (params,side) => { text = params.secondary_text; icon = drawIcon(params.secondary_icon); } - g.fillRect(0+x,24,119+x, 239); + g.fillRect(0+x,28,119+x, 239); g.setColor(0x000); g.setFont("Vector",15); g.setFontAlign(0,0.0); From 189633e966d9d9a0bd21d89b2eed9ddc195aeaa3 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 18:59:59 +0100 Subject: [PATCH 41/48] Modifying Home menu --- apps/BLEcontroller/app.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 4ed3a5eeb..d318994f1 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -234,7 +234,6 @@ const menuScreen = { right: speakBtn, btn1: "hover", btn2: "light", - btn3: "back" }; const speakScreen = { @@ -299,6 +298,12 @@ const Home = new State({ state: "DalekMenu", screen: menuScreen, events: (event) => { + if ((event.object == "top") && (event.status == "end")) { + return Lights; + } + if ((event.object == "middle") && (event.status == "end")) { + return Iris; + } if ((event.object == "right") && (event.status == "end")) { return Speak; } From c08303390ab098add4f703f59629aec2fced316d Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 19:16:03 +0100 Subject: [PATCH 42/48] Distinguish between iris controls --- apps/BLEcontroller/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index d318994f1..27e629d5d 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -338,12 +338,12 @@ const Iris = new State({ } if ((event.object == "right") && (event.status == "end")) { status_iris_light.value = !status_iris_light.value; - transmit(this.state, "iris_light", onOff(status_iris_light.value)); + transmit(this.state, "light", onOff(status_iris_light.value)); return this; } if ((event.object == "left") && (event.status == "end")) { status_iris.value = !status_iris.value; - transmit(this.state, "iris_servo", onOff(status_iris.value)); + transmit(this.state, "servo", onOff(status_iris.value)); return this; } transmit(this.state, event.object, event.status); From 07310e35364a7f6904d6e3942dcd313fd39ea7e2 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 19:36:21 +0100 Subject: [PATCH 43/48] Testing joystick variant --- apps/BLEcontroller/{app-joy.js => app-ex2.js} | 287 +++++++++--------- apps/BLEcontroller/app.js | 287 +++++++++--------- 2 files changed, 287 insertions(+), 287 deletions(-) rename apps/BLEcontroller/{app-joy.js => app-ex2.js} (66%) diff --git a/apps/BLEcontroller/app-joy.js b/apps/BLEcontroller/app-ex2.js similarity index 66% rename from apps/BLEcontroller/app-joy.js rename to apps/BLEcontroller/app-ex2.js index 8da1aadcb..27e629d5d 100644 --- a/apps/BLEcontroller/app-joy.js +++ b/apps/BLEcontroller/app-ex2.js @@ -19,18 +19,18 @@ bottom_btn = false; msgNum = 0; // message number -NRF.setConnectionInterval(100); -Bangle.loadWidgets(); -Bangle.drawWidgets(); /* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_auto = {value: false}; -var status_chess = {value: false}; -var status_wake = {value: false}; +var status_spk = {value: true}; +var status_face = {value: true}; +var status_iris_light = {value: false}; +var status_iris = {value: false}; +var status_hover = {value: false}; +var status_dome = {value: false}; /* trsnsmit message where @@ -69,49 +69,21 @@ Add an additional element to the icons array with a unique name and the data from the Image Object */ const icons = [ - { - name: "walk", - data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" - }, - { - name: "sit", - data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" - }, - { - name: "joystick", - data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" - }, - { - name: "left", - data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" - }, - { - name: "right", - data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" - }, - { - name: "forward", - data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" - }, - { - name: "backward", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" - }, { name: "back", data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" }, { - name: "mic_on", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" + name: "spk_on", + data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" + }, + { + name: "spk_off", + data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" }, { - name: "comms", - data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" - }, - { - name: "pawn", - data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" + name: "facerecog", + data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" }, { name: "sleep", @@ -122,12 +94,28 @@ const icons = [ data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" }, { - name: "wag_h", - data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" + name: "happy", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" }, { - name: "wag_v", - data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" + name: "sad", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" + }, + { + name: "hover", + data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" + }, + { + name: "light", + data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" + }, + { + name: "speak", + data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" + }, + { + name: "dalek", + data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" } ]; @@ -157,69 +145,79 @@ the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var joystickBtn = { +var happyBtn = { primary_colour: 0x653E, - primary_icon: 'joystick', - primary_text: 'Joystick', + primary_text: 'Speak', + primary_icon: 'happy', }; -var turnLeftBtn = { - primary_colour: 0x653E, - primary_text: 'Left', - primary_icon: 'left', - }; - -var turnRightBtn = { +var sadBtn = { primary_colour: 0x33F9, - primary_text: 'Right', - primary_icon: 'right', + primary_text: 'Speak', + primary_icon: 'sad', }; -var tailHBtn = { - primary_colour: 0x653E, - primary_text: 'Wag Tail', - primary_icon: 'wag_h', - }; - -var tailVBtn = { +var speakBtn = { primary_colour: 0x33F9, - primary_text: 'Wag Tail', - primary_icon: 'wag_v', + primary_text: 'Speak', + primary_icon: 'speak', }; -var chessBtn = { +var faceBtn = { primary_colour: 0xE9C7, primary_text: 'Off', - primary_icon: 'pawn', + primary_icon: 'facerecog', toggle: true, secondary_colour: 0x3F48, secondary_text: 'On', - secondary_icon : 'pawn', - value: status_chess + secondary_icon : 'facerecog', + value: status_face }; -var wakeBtn = { +var irisLightBtn = { primary_colour: 0xE9C7, - primary_text: 'Sleeping', + primary_text: 'Off', + primary_icon: 'light', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'light', + value: status_iris_light + }; + +var irisBtn = { + primary_colour: 0xE9C7, + primary_text: 'Closed', primary_icon: 'sleep', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Awake', + secondary_text: 'Open', secondary_icon : 'awake', - value: status_wake + value: status_iris }; -var autoBtn = { +var hoverBtn = { primary_colour: 0xE9C7, - primary_text: 'Stop', - primary_icon: 'sit', + primary_text: 'Off', + primary_icon: 'hover', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Move', - secondary_icon : 'walk', - value: status_auto + secondary_text: 'On', + secondary_icon : 'hover', + value: status_hover }; + var domeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'dalek', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'dalek', + value: status_dome + }; + /* CONFIGURATION AREA - SCREEN DEFINITIONS a screen can have a button (as defined above) @@ -230,35 +228,32 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ + const menuScreen = { - left: wakeBtn, - right: joystickBtn, - btn1: "pawn", - btn2: "wag_h", + left: faceBtn, + right: speakBtn, + btn1: "hover", + btn2: "light", +}; + +const speakScreen = { + left: happyBtn, + right: sadBtn, btn3: "back" }; -const joystickScreen = { - left: turnLeftBtn, - right: turnRightBtn, - btn1: "forward", - btn2: "backward", +const irisScreen = { + left: irisBtn, + right: irisLightBtn, btn3: "back" }; -const tailScreen = { - left: tailHBtn, - right: tailVBtn, +const lightsScreen = { + left: hoverBtn, + right: domeBtn, btn3: "back" }; -const chessScreen = { - left: chessBtn, - right: autoBtn, - btn3: "back" -}; - - /* base state definition Each of the screens correspond to a state; this class provides a constuctor for each @@ -293,22 +288,28 @@ one, then the state machine will change to that new State and redrsw the screen appropriately. To add in additional capabilities for button presses, simply add an additional 'if' statement. -For toggle buttons, the value of the appropiate status object is +For toggle buttons, the value of the sppropiate status object is inversed and the new value transmitted. */ /* The Home State/Page is where the application beings */ const Home = new State({ - state: "K9Menu", + state: "DalekMenu", screen: menuScreen, events: (event) => { + if ((event.object == "top") && (event.status == "end")) { + return Lights; + } + if ((event.object == "middle") && (event.status == "end")) { + return Iris; + } if ((event.object == "right") && (event.status == "end")) { - return Joystick; + return Speak; } if ((event.object == "left") && (event.status == "end")) { - status_wake.value = !status_wake.value; - transmit(this.state, "wake", onOff(status_wake.value)); + status_face.value = !status_face.value; + transmit(this.state, "face", onOff(status_face.value)); return this; } transmit(this.state, event.object, event.status); @@ -316,31 +317,9 @@ const Home = new State({ } }); -const Chess = new State({ - state: "Chess", - screen: chessScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_auto.value = !status_auto.value; - transmit(this.state, "follow", onOff(status_auto.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_chess.value = !status_chess.value; - transmit(this.state, "chess", onOff(status_chess.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Tail = new State({ - state: "Tail", - screen: tailScreen, +const Speak = new State({ + state: "Speak", + screen: speakScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; @@ -350,18 +329,48 @@ const Tail = new State({ } }); -/* Joystick page state */ -const Joystick = new State({ - state: "Joystick", - screen: joystickScreen, +const Iris = new State({ + state: "Iris", + screen: irisScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { - transmit("Joystick", "joystick", "off"); - return Home; - } + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_iris_light.value = !status_iris_light.value; + transmit(this.state, "light", onOff(status_iris_light.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_iris.value = !status_iris.value; + transmit(this.state, "servo", onOff(status_iris.value)); + return this; + } transmit(this.state, event.object, event.status); return this; - } + } +}); + +const Lights = new State({ + state: "Lights", + screen: lightsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_dome.value = !status_dome.value; + transmit(this.state, "dome", onOff(status_dome.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_hover.value = !status_hover.value; + transmit(this.state, "hover", onOff(status_hover.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } }); /* translate button status into english */ @@ -417,7 +426,7 @@ const drawButton = (params,side) => { text = params.secondary_text; icon = drawIcon(params.secondary_icon); } - g.fillRect(0+x,28,119+x, 239); + g.fillRect(0+x,24,119+x, 239); g.setColor(0x000); g.setFont("Vector",15); g.setFontAlign(0,0.0); diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 27e629d5d..8da1aadcb 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -19,18 +19,18 @@ bottom_btn = false; msgNum = 0; // message number +NRF.setConnectionInterval(100); +Bangle.loadWidgets(); +Bangle.drawWidgets(); /* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_spk = {value: true}; -var status_face = {value: true}; -var status_iris_light = {value: false}; -var status_iris = {value: false}; -var status_hover = {value: false}; -var status_dome = {value: false}; +var status_auto = {value: false}; +var status_chess = {value: false}; +var status_wake = {value: false}; /* trsnsmit message where @@ -69,21 +69,49 @@ Add an additional element to the icons array with a unique name and the data from the Image Object */ const icons = [ + { + name: "walk", + data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" + }, + { + name: "sit", + data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" + }, + { + name: "joystick", + data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" + }, + { + name: "left", + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + }, + { + name: "right", + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + }, + { + name: "forward", + data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" + }, + { + name: "backward", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" + }, { name: "back", data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" }, { - name: "spk_on", - data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" - }, - { - name: "spk_off", - data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" + name: "mic_on", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" }, { - name: "facerecog", - data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" + name: "comms", + data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + }, + { + name: "pawn", + data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" }, { name: "sleep", @@ -94,28 +122,12 @@ const icons = [ data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" }, { - name: "happy", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" + name: "wag_h", + data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" }, { - name: "sad", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" - }, - { - name: "hover", - data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" - }, - { - name: "light", - data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" - }, - { - name: "speak", - data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" - }, - { - name: "dalek", - data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" + name: "wag_v", + data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" } ]; @@ -145,79 +157,69 @@ the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var happyBtn = { +var joystickBtn = { primary_colour: 0x653E, - primary_text: 'Speak', - primary_icon: 'happy', + primary_icon: 'joystick', + primary_text: 'Joystick', }; -var sadBtn = { +var turnLeftBtn = { + primary_colour: 0x653E, + primary_text: 'Left', + primary_icon: 'left', + }; + +var turnRightBtn = { primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'sad', + primary_text: 'Right', + primary_icon: 'right', }; -var speakBtn = { +var tailHBtn = { + primary_colour: 0x653E, + primary_text: 'Wag Tail', + primary_icon: 'wag_h', + }; + +var tailVBtn = { primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'speak', + primary_text: 'Wag Tail', + primary_icon: 'wag_v', }; -var faceBtn = { +var chessBtn = { primary_colour: 0xE9C7, primary_text: 'Off', - primary_icon: 'facerecog', + primary_icon: 'pawn', toggle: true, secondary_colour: 0x3F48, secondary_text: 'On', - secondary_icon : 'facerecog', - value: status_face + secondary_icon : 'pawn', + value: status_chess }; -var irisLightBtn = { +var wakeBtn = { primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'light', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'light', - value: status_iris_light - }; - -var irisBtn = { - primary_colour: 0xE9C7, - primary_text: 'Closed', + primary_text: 'Sleeping', primary_icon: 'sleep', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Open', + secondary_text: 'Awake', secondary_icon : 'awake', - value: status_iris + value: status_wake }; -var hoverBtn = { +var autoBtn = { primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'hover', + primary_text: 'Stop', + primary_icon: 'sit', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'hover', - value: status_hover + secondary_text: 'Move', + secondary_icon : 'walk', + value: status_auto }; - var domeBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'dalek', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'dalek', - value: status_dome - }; - /* CONFIGURATION AREA - SCREEN DEFINITIONS a screen can have a button (as defined above) @@ -228,32 +230,35 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ - const menuScreen = { - left: faceBtn, - right: speakBtn, - btn1: "hover", - btn2: "light", -}; - -const speakScreen = { - left: happyBtn, - right: sadBtn, + left: wakeBtn, + right: joystickBtn, + btn1: "pawn", + btn2: "wag_h", btn3: "back" }; -const irisScreen = { - left: irisBtn, - right: irisLightBtn, +const joystickScreen = { + left: turnLeftBtn, + right: turnRightBtn, + btn1: "forward", + btn2: "backward", btn3: "back" }; -const lightsScreen = { - left: hoverBtn, - right: domeBtn, +const tailScreen = { + left: tailHBtn, + right: tailVBtn, btn3: "back" }; +const chessScreen = { + left: chessBtn, + right: autoBtn, + btn3: "back" +}; + + /* base state definition Each of the screens correspond to a state; this class provides a constuctor for each @@ -288,28 +293,22 @@ one, then the state machine will change to that new State and redrsw the screen appropriately. To add in additional capabilities for button presses, simply add an additional 'if' statement. -For toggle buttons, the value of the sppropiate status object is +For toggle buttons, the value of the appropiate status object is inversed and the new value transmitted. */ /* The Home State/Page is where the application beings */ const Home = new State({ - state: "DalekMenu", + state: "K9Menu", screen: menuScreen, events: (event) => { - if ((event.object == "top") && (event.status == "end")) { - return Lights; - } - if ((event.object == "middle") && (event.status == "end")) { - return Iris; - } if ((event.object == "right") && (event.status == "end")) { - return Speak; + return Joystick; } if ((event.object == "left") && (event.status == "end")) { - status_face.value = !status_face.value; - transmit(this.state, "face", onOff(status_face.value)); + status_wake.value = !status_wake.value; + transmit(this.state, "wake", onOff(status_wake.value)); return this; } transmit(this.state, event.object, event.status); @@ -317,9 +316,31 @@ const Home = new State({ } }); -const Speak = new State({ - state: "Speak", - screen: speakScreen, +const Chess = new State({ + state: "Chess", + screen: chessScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_auto.value = !status_auto.value; + transmit(this.state, "follow", onOff(status_auto.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_chess.value = !status_chess.value; + transmit(this.state, "chess", onOff(status_chess.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Tail = new State({ + state: "Tail", + screen: tailScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; @@ -329,48 +350,18 @@ const Speak = new State({ } }); -const Iris = new State({ - state: "Iris", - screen: irisScreen, +/* Joystick page state */ +const Joystick = new State({ + state: "Joystick", + screen: joystickScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_iris_light.value = !status_iris_light.value; - transmit(this.state, "light", onOff(status_iris_light.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_iris.value = !status_iris.value; - transmit(this.state, "servo", onOff(status_iris.value)); - return this; - } + transmit("Joystick", "joystick", "off"); + return Home; + } transmit(this.state, event.object, event.status); return this; - } -}); - -const Lights = new State({ - state: "Lights", - screen: lightsScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_dome.value = !status_dome.value; - transmit(this.state, "dome", onOff(status_dome.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_hover.value = !status_hover.value; - transmit(this.state, "hover", onOff(status_hover.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } + } }); /* translate button status into english */ @@ -426,7 +417,7 @@ const drawButton = (params,side) => { text = params.secondary_text; icon = drawIcon(params.secondary_icon); } - g.fillRect(0+x,24,119+x, 239); + g.fillRect(0+x,28,119+x, 239); g.setColor(0x000); g.setFont("Vector",15); g.setFontAlign(0,0.0); From 39fc56f0b060384952750d4b38ebd7bbedd95931 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 20:16:26 +0100 Subject: [PATCH 44/48] Enabling navigation to sub-screens --- apps/BLEcontroller/app.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 8da1aadcb..0735aeee6 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -234,8 +234,7 @@ const menuScreen = { left: wakeBtn, right: joystickBtn, btn1: "pawn", - btn2: "wag_h", - btn3: "back" + btn2: "wag_v", }; const joystickScreen = { @@ -303,6 +302,12 @@ const Home = new State({ state: "K9Menu", screen: menuScreen, events: (event) => { + if ((event.object == "top") && (event.status == "end")) { + return Chess; + } + if ((event.object == "middle") && (event.status == "end")) { + return Tail; + } if ((event.object == "right") && (event.status == "end")) { return Joystick; } From 65e5a2a5443cfe5931add37c0226c1ba57960edd Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 20:34:04 +0100 Subject: [PATCH 45/48] Final changes before pull request --- apps/BLEcontroller/Bangle.code-workspace | 7 - .../{app.js.old.js => app-joy.js} | 256 ++++++++++++------ apps/BLEcontroller/app.js | 232 ++++++---------- apps/BLEcontroller/video.png | Bin 178721 -> 0 bytes 4 files changed, 244 insertions(+), 251 deletions(-) delete mode 100644 apps/BLEcontroller/Bangle.code-workspace rename apps/BLEcontroller/{app.js.old.js => app-joy.js} (66%) delete mode 100644 apps/BLEcontroller/video.png diff --git a/apps/BLEcontroller/Bangle.code-workspace b/apps/BLEcontroller/Bangle.code-workspace deleted file mode 100644 index 90587e88f..000000000 --- a/apps/BLEcontroller/Bangle.code-workspace +++ /dev/null @@ -1,7 +0,0 @@ -{ - "folders": [ - { - "path": "/Users/hopkira/Documents/BangleApps" - } - ] -} \ No newline at end of file diff --git a/apps/BLEcontroller/app.js.old.js b/apps/BLEcontroller/app-joy.js similarity index 66% rename from apps/BLEcontroller/app.js.old.js rename to apps/BLEcontroller/app-joy.js index c8217988c..0735aeee6 100644 --- a/apps/BLEcontroller/app.js.old.js +++ b/apps/BLEcontroller/app-joy.js @@ -28,10 +28,9 @@ declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_printer = {value: false}; -var status_tv = {value: false}; -var status_light_hall = {value: false}; -var status_light_study = {value: false}; +var status_auto = {value: false}; +var status_chess = {value: false}; +var status_wake = {value: false}; /* trsnsmit message where @@ -71,16 +70,64 @@ with a unique name and the data from the Image Object */ const icons = [ { - name: "switch", - data: "gEBAP4B/AP4B/AP4B/AMgA3HPJdlVvI7/Hf47/Hf47/Hf47/Hf47/Hf4AvIPKRXAP4B/AP4B/AP4B/AJgA==" + name: "walk", + data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" }, { - name: "light", - data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" + name: "sit", + data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" + }, + { + name: "joystick", + data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" + }, + { + name: "left", + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + }, + { + name: "right", + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + }, + { + name: "forward", + data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" + }, + { + name: "backward", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" }, { name: "back", data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "mic_on", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" + }, + { + name: "comms", + data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + }, + { + name: "pawn", + data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "wag_h", + data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" + }, + { + name: "wag_v", + data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" } ]; @@ -110,61 +157,68 @@ the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var lightBtn = { +var joystickBtn = { primary_colour: 0x653E, - primary_text: 'Lights', - primary_icon: 'light', + primary_icon: 'joystick', + primary_text: 'Joystick', }; -var socketsBtn = { +var turnLeftBtn = { + primary_colour: 0x653E, + primary_text: 'Left', + primary_icon: 'left', + }; + +var turnRightBtn = { primary_colour: 0x33F9, - primary_text: 'Sockets', - primary_icon: 'switch', + primary_text: 'Right', + primary_icon: 'right', }; -var lightHallBtn = { - primary_colour: 0xE9C7, - primary_text: 'Hall Off', - primary_icon: 'light', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Hall On', - secondary_icon : 'light', - value: status_light_hall +var tailHBtn = { + primary_colour: 0x653E, + primary_text: 'Wag Tail', + primary_icon: 'wag_h', }; -var lightStudyBtn = { - primary_colour: 0xE9C7, - primary_text: 'Study Off', - primary_icon: 'light', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Study On', - secondary_icon : 'light', - value: status_light_study -}; - -var socketTVBtn = { - primary_colour: 0xE9C7, - primary_text: 'TV Off', - primary_icon: 'switch', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'TV On', - secondary_icon : 'switch', - value: status_tv +var tailVBtn = { + primary_colour: 0x33F9, + primary_text: 'Wag Tail', + primary_icon: 'wag_v', }; -var socketPrinterBtn = { +var chessBtn = { primary_colour: 0xE9C7, - primary_text: 'Printer Off', - primary_icon: 'switch', + primary_text: 'Off', + primary_icon: 'pawn', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Printer On', - secondary_icon : 'switch', - value: status_printer -}; + secondary_text: 'On', + secondary_icon : 'pawn', + value: status_chess + }; + +var wakeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Sleeping', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Awake', + secondary_icon : 'awake', + value: status_wake + }; + +var autoBtn = { + primary_colour: 0xE9C7, + primary_text: 'Stop', + primary_icon: 'sit', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Move', + secondary_icon : 'walk', + value: status_auto + }; /* CONFIGURATION AREA - SCREEN DEFINITIONS @@ -176,23 +230,34 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ -const homeScreen = { - left: lightBtn, - right: socketsBtn, +const menuScreen = { + left: wakeBtn, + right: joystickBtn, + btn1: "pawn", + btn2: "wag_v", }; -const lightsScreen = { - left: lightHallBtn, - right: lightStudyBtn, +const joystickScreen = { + left: turnLeftBtn, + right: turnRightBtn, + btn1: "forward", + btn2: "backward", btn3: "back" }; -const socketsScreen = { - left: socketTVBtn, - right: socketPrinterBtn, +const tailScreen = { + left: tailHBtn, + right: tailVBtn, btn3: "back" }; +const chessScreen = { + left: chessBtn, + right: autoBtn, + btn3: "back" +}; + + /* base state definition Each of the screens correspond to a state; this class provides a constuctor for each @@ -232,36 +297,23 @@ inversed and the new value transmitted. */ /* The Home State/Page is where the application beings */ + const Home = new State({ - state: "Home", - screen: homeScreen, + state: "K9Menu", + screen: menuScreen, events: (event) => { - if ((event.object == "right") && (event.status == "end")) { - return SocketsMenu; + if ((event.object == "top") && (event.status == "end")) { + return Chess; } - if ((event.object == "left") && (event.status == "end")) { - return LightsMenu; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const LightsMenu = new State({ - state: "LightsMenu", - screen: lightsScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; + if ((event.object == "middle") && (event.status == "end")) { + return Tail; } if ((event.object == "right") && (event.status == "end")) { - status_light_study.value = !status_light_study.value; - transmit(this.state, "study", onOff(status_light_study.value)); - return this; + return Joystick; } if ((event.object == "left") && (event.status == "end")) { - status_light_hall.value = !status_light_hall.value; - transmit(this.state, "hall", onOff(status_light_hall.value)); + status_wake.value = !status_wake.value; + transmit(this.state, "wake", onOff(status_wake.value)); return this; } transmit(this.state, event.object, event.status); @@ -269,21 +321,21 @@ const LightsMenu = new State({ } }); -const SocketsMenu = new State({ - state: "SocketsMenu", - screen: socketsScreen, +const Chess = new State({ + state: "Chess", + screen: chessScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; } if ((event.object == "right") && (event.status == "end")) { - status_printer.value = !status_printer.value; - transmit(this.state, "printer", onOff(status_printer.value)); + status_auto.value = !status_auto.value; + transmit(this.state, "follow", onOff(status_auto.value)); return this; } if ((event.object == "left") && (event.status == "end")) { - status_tv.value = !status_tv.value; - transmit(this.state, "tv", onOff(status_tv.value)); + status_chess.value = !status_chess.value; + transmit(this.state, "chess", onOff(status_chess.value)); return this; } transmit(this.state, event.object, event.status); @@ -291,6 +343,32 @@ const SocketsMenu = new State({ } }); +const Tail = new State({ + state: "Tail", + screen: tailScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* Joystick page state */ +const Joystick = new State({ + state: "Joystick", + screen: joystickScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + transmit("Joystick", "joystick", "off"); + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + /* translate button status into english */ const startEnd = status => status ? "start" : "end"; diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 0735aeee6..c8217988c 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -28,9 +28,10 @@ declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_auto = {value: false}; -var status_chess = {value: false}; -var status_wake = {value: false}; +var status_printer = {value: false}; +var status_tv = {value: false}; +var status_light_hall = {value: false}; +var status_light_study = {value: false}; /* trsnsmit message where @@ -70,64 +71,16 @@ with a unique name and the data from the Image Object */ const icons = [ { - name: "walk", - data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" + name: "switch", + data: "gEBAP4B/AP4B/AP4B/AMgA3HPJdlVvI7/Hf47/Hf47/Hf47/Hf47/Hf4AvIPKRXAP4B/AP4B/AP4B/AJgA==" }, { - name: "sit", - data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" - }, - { - name: "joystick", - data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" - }, - { - name: "left", - data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" - }, - { - name: "right", - data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" - }, - { - name: "forward", - data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" - }, - { - name: "backward", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" + name: "light", + data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" }, { name: "back", data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" - }, - { - name: "mic_on", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" - }, - { - name: "comms", - data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" - }, - { - name: "pawn", - data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" - }, - { - name: "sleep", - data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" - }, - { - name: "awake", - data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" - }, - { - name: "wag_h", - data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" - }, - { - name: "wag_v", - data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" } ]; @@ -157,68 +110,61 @@ the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var joystickBtn = { +var lightBtn = { primary_colour: 0x653E, - primary_icon: 'joystick', - primary_text: 'Joystick', + primary_text: 'Lights', + primary_icon: 'light', }; -var turnLeftBtn = { - primary_colour: 0x653E, - primary_text: 'Left', - primary_icon: 'left', - }; - -var turnRightBtn = { +var socketsBtn = { primary_colour: 0x33F9, - primary_text: 'Right', - primary_icon: 'right', + primary_text: 'Sockets', + primary_icon: 'switch', }; -var tailHBtn = { - primary_colour: 0x653E, - primary_text: 'Wag Tail', - primary_icon: 'wag_h', - }; - -var tailVBtn = { - primary_colour: 0x33F9, - primary_text: 'Wag Tail', - primary_icon: 'wag_v', - }; - -var chessBtn = { +var lightHallBtn = { primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'pawn', + primary_text: 'Hall Off', + primary_icon: 'light', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'pawn', - value: status_chess + secondary_text: 'Hall On', + secondary_icon : 'light', + value: status_light_hall }; -var wakeBtn = { +var lightStudyBtn = { primary_colour: 0xE9C7, - primary_text: 'Sleeping', - primary_icon: 'sleep', + primary_text: 'Study Off', + primary_icon: 'light', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Awake', - secondary_icon : 'awake', - value: status_wake + secondary_text: 'Study On', + secondary_icon : 'light', + value: status_light_study +}; + +var socketTVBtn = { + primary_colour: 0xE9C7, + primary_text: 'TV Off', + primary_icon: 'switch', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'TV On', + secondary_icon : 'switch', + value: status_tv }; -var autoBtn = { +var socketPrinterBtn = { primary_colour: 0xE9C7, - primary_text: 'Stop', - primary_icon: 'sit', + primary_text: 'Printer Off', + primary_icon: 'switch', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Move', - secondary_icon : 'walk', - value: status_auto - }; + secondary_text: 'Printer On', + secondary_icon : 'switch', + value: status_printer +}; /* CONFIGURATION AREA - SCREEN DEFINITIONS @@ -230,34 +176,23 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ -const menuScreen = { - left: wakeBtn, - right: joystickBtn, - btn1: "pawn", - btn2: "wag_v", +const homeScreen = { + left: lightBtn, + right: socketsBtn, }; -const joystickScreen = { - left: turnLeftBtn, - right: turnRightBtn, - btn1: "forward", - btn2: "backward", +const lightsScreen = { + left: lightHallBtn, + right: lightStudyBtn, btn3: "back" }; -const tailScreen = { - left: tailHBtn, - right: tailVBtn, +const socketsScreen = { + left: socketTVBtn, + right: socketPrinterBtn, btn3: "back" }; -const chessScreen = { - left: chessBtn, - right: autoBtn, - btn3: "back" -}; - - /* base state definition Each of the screens correspond to a state; this class provides a constuctor for each @@ -297,45 +232,36 @@ inversed and the new value transmitted. */ /* The Home State/Page is where the application beings */ - const Home = new State({ - state: "K9Menu", - screen: menuScreen, + state: "Home", + screen: homeScreen, events: (event) => { - if ((event.object == "top") && (event.status == "end")) { - return Chess; - } - if ((event.object == "middle") && (event.status == "end")) { - return Tail; - } if ((event.object == "right") && (event.status == "end")) { - return Joystick; + return SocketsMenu; } if ((event.object == "left") && (event.status == "end")) { - status_wake.value = !status_wake.value; - transmit(this.state, "wake", onOff(status_wake.value)); - return this; + return LightsMenu; } transmit(this.state, event.object, event.status); return this; } }); -const Chess = new State({ - state: "Chess", - screen: chessScreen, +const LightsMenu = new State({ + state: "LightsMenu", + screen: lightsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; } if ((event.object == "right") && (event.status == "end")) { - status_auto.value = !status_auto.value; - transmit(this.state, "follow", onOff(status_auto.value)); + status_light_study.value = !status_light_study.value; + transmit(this.state, "study", onOff(status_light_study.value)); return this; } if ((event.object == "left") && (event.status == "end")) { - status_chess.value = !status_chess.value; - transmit(this.state, "chess", onOff(status_chess.value)); + status_light_hall.value = !status_light_hall.value; + transmit(this.state, "hall", onOff(status_light_hall.value)); return this; } transmit(this.state, event.object, event.status); @@ -343,32 +269,28 @@ const Chess = new State({ } }); -const Tail = new State({ - state: "Tail", - screen: tailScreen, +const SocketsMenu = new State({ + state: "SocketsMenu", + screen: socketsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; } + if ((event.object == "right") && (event.status == "end")) { + status_printer.value = !status_printer.value; + transmit(this.state, "printer", onOff(status_printer.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_tv.value = !status_tv.value; + transmit(this.state, "tv", onOff(status_tv.value)); + return this; + } transmit(this.state, event.object, event.status); return this; } }); -/* Joystick page state */ -const Joystick = new State({ - state: "Joystick", - screen: joystickScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - transmit("Joystick", "joystick", "off"); - return Home; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - /* translate button status into english */ const startEnd = status => status ? "start" : "end"; diff --git a/apps/BLEcontroller/video.png b/apps/BLEcontroller/video.png deleted file mode 100644 index bd25e26a240e53ad6b09e0ba5eb1ab950f966d2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178721 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�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 Date: Mon, 1 Jun 2020 21:35:43 +0100 Subject: [PATCH 46/48] Added K9 controller --- apps.json | 14 ++ apps/k9control/README.md | 50 ++++ apps/k9control/app-icon.js | 1 + apps/k9control/app.js | 446 ++++++++++++++++++++++++++++++++++ apps/k9control/k9_icon_30.png | Bin 0 -> 4779 bytes 5 files changed, 511 insertions(+) create mode 100644 apps/k9control/README.md create mode 100644 apps/k9control/app-icon.js create mode 100644 apps/k9control/app.js create mode 100644 apps/k9control/k9_icon_30.png diff --git a/apps.json b/apps.json index bdc831069..56025ac3d 100644 --- a/apps.json +++ b/apps.json @@ -1785,6 +1785,20 @@ { "name": "BLEcontroller.img", "url": "app-icon.js", "evaluate": true } ] }, + { "id": "k9control", + "name": "K9 BLE Controller with Joystick", + "shortName": "K9 Controller", + "icon": "k9_icon_30.png", + "version": "0.01", + "description": "My private K9 BLE controller", + "tags": "tool,bluetooth", + "readme": "README.md", + "allow_emulator":false, + "storage": [ + { "name": "k9control.app.js", "url": "app.js" }, + { "name": "k9control.img", "url": "app-icon.js", "evaluate": true } + ] + }, { "id": "widviz", "name": "Widget Visibility Widget", "shortName":"Viz Widget", diff --git a/apps/k9control/README.md b/apps/k9control/README.md new file mode 100644 index 000000000..6ce68efb3 --- /dev/null +++ b/apps/k9control/README.md @@ -0,0 +1,50 @@ +# K9 BLE Controller with Joystick + +A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. + +Amaze your friends by controlling your robot, your house or any other BLE device from your watch! + + + +To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: +* message number (up to the least significant four digits) +* screen name (up to four characters) +* object name (up to four characters) +* value/status (up to four characters) + +The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. + +Gordon Williams' EspruinoHub is an excellent way to transform thse BLE advertisements into MQTT messages for further processing. They can be subscribed to via the following MQTT topic (change the watchaddress, to the MAC address of your Bangle.js) +/ble/advertise/wa:tc:ha:dd:re:ss/espruino/# + +## Usage + +The application can be configured at will by changing the definitions of the screens, events, icons and buttons. + +Most changes are possible via data, rather than code change. + +## Features + +The default package contains three configurations: +* a simple home light and sockets controller UI (app.js) +* a robot controller UI with joystick (app-joy.js) +* a simple static assistant controller (app-ex2.js) + +You can try out the other configurations by deleting app.js and renaming the file you want to try as app.js. + +I have tested out the application to as many as eight screens without problems, but four screens are usually enough for most situations. + +## Controls + +The controls will vary by screen, but I suggest a convention of using BTN3 (the bottom button) for moving backwards up the menu stack. + +I have used the convention of red/green for buttons that are switches and blue buttons that provide single function operation (such as navigating a menu or executing a on-off activity) + +## Requests + +In the first instance, please consult my blog post on this application [here](https://k9-build.blogspot.com/2020/05/controlling-k9-using-bluetooth-ble-from.html) + +## Creator + +Richard Hopkins, FIET CEng +May 2020 diff --git a/apps/k9control/app-icon.js b/apps/k9control/app-icon.js new file mode 100644 index 000000000..55d7fb3cc --- /dev/null +++ b/apps/k9control/app-icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("JyeEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiAAAAAAAAAAAAAAAAAAAAAAAAAiAAAAAAAAAAAAAAAAAAAAACIiIiAAAAAAAAAAAAAAAAAAAAACIiIgAAAAIAAAAAAAAAAAAAAAAiIiIiIAAAAiAAAAAAAAAAAAAAAiIiIiIAAAACIiAAAAAAAAAAAAAiIiIiIAAAAAAiIgAAAiIiIiIgAiIiIiIiAAAAAAIiIiIiIiIiIiIiIiIiIiIAAAAAACIiIiIiIiIiIiIiIiIiIgAAAAAAIiIiIiIiIiIiIiIiIiIiAAAAAAIiIiIiIiIiIiIgAiIiIgAAAAACIiIiIiIiIiIiIAACIiIAAAAAAiIiIiIiIiIiIiAAAAAAAAAAAAIiIiIiIiIiIiIiAAAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAAiIiIiIiIiIiIiIiAAAAAAAAAAAiIiIiIiIiIiIiIiIAAAAAAAAAAiIiIiIiIiIiIiIiIAAAAAAAAAIiIiIiIiIiIiIiIiIAAAAAAAAAIiIiIiIiIiIiIiIiIgAAAAAAACIiIiIiIiIiIiIiIiIgAAAAAAACIiIiIiIiIiIiIiIiIiAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")) diff --git a/apps/k9control/app.js b/apps/k9control/app.js new file mode 100644 index 000000000..0735aeee6 --- /dev/null +++ b/apps/k9control/app.js @@ -0,0 +1,446 @@ +/* +========================================================== +Simple event based robot controller that enables robot +to switch into automatic or manual control modes. Behaviours +are controlled via a simple finite state machine. +In automatic mode the +robot will look after itself. In manual mode, the watch +will provide simple forward, back, left and right commands. +The messages will be transmitted to a partner BLE Espruino +using BLE +Written by Richard Hopkins, May 2020 +========================================================== +declare global variables for watch button statuses */ +top_btn = false; +middle_btn = false; +left_btn= false; // the left side of the touch screen +right_btn = false; // the right side of the touch screen +bottom_btn = false; + +msgNum = 0; // message number + +NRF.setConnectionInterval(100); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +/* +CONFIGURATION AREA - STATE VARIABLES +declare global variables for the toggle button +statuses; if you add an additional toggle button +you should declare it and initiase it here */ + +var status_auto = {value: false}; +var status_chess = {value: false}; +var status_wake = {value: false}; + +/* trsnsmit message +where +s = first character of state, +o = first three character of object name +v = value of state.object +*/ + +const transmit = (state,object,status) => { + msgNum ++; + msg = { + n: msgNum.toString().slice(-4), + s: state.substr(0,4), + o: object.substr(0,4), + v: status.substr(0,4), + }; + message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; + NRF.setAdvertising({},{ + showName: false, + manufacturer: 0x0590, + manufacturerData: JSON.stringify(message)}); +}; + +/* +CONFIGURATION AREA - ICON DEFINITIONS +Retrieve 30px PNG icons from: +https://icons8.com/icon/set/speak/ios-glyphs +Create icons using: +https://www.espruino.com/Image+Converter +Use compression: true +Transparency: true +Diffusion: flat +Colours: 16bit RGB +Ouput as: Image Object +Add an additional element to the icons array +with a unique name and the data from the Image Object +*/ +const icons = [ + { + name: "walk", + data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" + }, + { + name: "sit", + data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" + }, + { + name: "joystick", + data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" + }, + { + name: "left", + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + }, + { + name: "right", + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + }, + { + name: "forward", + data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" + }, + { + name: "backward", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" + }, + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "mic_on", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" + }, + { + name: "comms", + data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + }, + { + name: "pawn", + data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "wag_h", + data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" + }, + { + name: "wag_v", + data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" + } + ]; + +/* finds icon data by name in the icon array and returns an image object*/ +const drawIcon = (name) => { + for (var icon of icons) { + if (icon.name == name) { + image = { + width : 30, height : 30, bpp : 16, + transparent : 1, + buffer: require("heatshrink").decompress(atob(icon.data)) + }; + return image;} + } +}; + +/* +CONFIGURATION AREA - BUTTON DEFINITIONS +for a simple button, just define a primary colour +and an icon name from the icon array and +the text to display beneath the button +for toggle buttons, additionally provide secondary +colours, icon name and text. Also provide a reference +to a global variable for the value of the button. +The global variable should be declared at the start of +the program and it may be adviable to use the 'status_name' +format to ensure it is clear. +*/ + +var joystickBtn = { + primary_colour: 0x653E, + primary_icon: 'joystick', + primary_text: 'Joystick', + }; + +var turnLeftBtn = { + primary_colour: 0x653E, + primary_text: 'Left', + primary_icon: 'left', + }; + +var turnRightBtn = { + primary_colour: 0x33F9, + primary_text: 'Right', + primary_icon: 'right', + }; + +var tailHBtn = { + primary_colour: 0x653E, + primary_text: 'Wag Tail', + primary_icon: 'wag_h', + }; + +var tailVBtn = { + primary_colour: 0x33F9, + primary_text: 'Wag Tail', + primary_icon: 'wag_v', + }; + +var chessBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'pawn', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'pawn', + value: status_chess + }; + +var wakeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Sleeping', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Awake', + secondary_icon : 'awake', + value: status_wake + }; + +var autoBtn = { + primary_colour: 0xE9C7, + primary_text: 'Stop', + primary_icon: 'sit', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Move', + secondary_icon : 'walk', + value: status_auto + }; + +/* +CONFIGURATION AREA - SCREEN DEFINITIONS +a screen can have a button (as defined above) +on the left and/or the right of the screen. +in adddition a screen can optionally have +an icon for each of the three buttons on +the left hand side of the screen. These +are defined as btn1, bt2 and bt3. The +values are names from the icon array. +*/ +const menuScreen = { + left: wakeBtn, + right: joystickBtn, + btn1: "pawn", + btn2: "wag_v", +}; + +const joystickScreen = { + left: turnLeftBtn, + right: turnRightBtn, + btn1: "forward", + btn2: "backward", + btn3: "back" +}; + +const tailScreen = { + left: tailHBtn, + right: tailVBtn, + btn3: "back" +}; + +const chessScreen = { + left: chessBtn, + right: autoBtn, + btn3: "back" +}; + + +/* base state definition +Each of the screens correspond to a state; +this class provides a constuctor for each +of the states +*/ +class State { + constructor(params) { + this.state = params.state; + this.events = params.events; + this.screen = params.screen; + } +} + +/* +CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS +This area defines how each screen behaves. +Each screen corresponds to a different State of the +state machine. This makes it much easier to isolate +behaviours between screens. +The state value is transmitted whenever a button is pressed +to provide context (so the receiving device, knows which +button was pressed on which screen). +The screens are defined above. +The events section identifies if a particular button has been +pressed and released on the screen and an action can then be taken. +The events function receives a notification from a mySetWatch which +provides an event object that identifies which button and whether +it has been pressed down or released. Actions can then be taken. +The events function will always return a State object. +If the events function returns different State from the current +one, then the state machine will change to that new State and redrsw +the screen appropriately. +To add in additional capabilities for button presses, simply add +an additional 'if' statement. +For toggle buttons, the value of the appropiate status object is +inversed and the new value transmitted. +*/ + +/* The Home State/Page is where the application beings */ + +const Home = new State({ + state: "K9Menu", + screen: menuScreen, + events: (event) => { + if ((event.object == "top") && (event.status == "end")) { + return Chess; + } + if ((event.object == "middle") && (event.status == "end")) { + return Tail; + } + if ((event.object == "right") && (event.status == "end")) { + return Joystick; + } + if ((event.object == "left") && (event.status == "end")) { + status_wake.value = !status_wake.value; + transmit(this.state, "wake", onOff(status_wake.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Chess = new State({ + state: "Chess", + screen: chessScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_auto.value = !status_auto.value; + transmit(this.state, "follow", onOff(status_auto.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_chess.value = !status_chess.value; + transmit(this.state, "chess", onOff(status_chess.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Tail = new State({ + state: "Tail", + screen: tailScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* Joystick page state */ +const Joystick = new State({ + state: "Joystick", + screen: joystickScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + transmit("Joystick", "joystick", "off"); + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* translate button status into english */ +const startEnd = status => status ? "start" : "end"; + +/* translate status into english */ +const onOff= status => status ? "on" : "off"; + + +/* create watching functions that will change the global +button status when pressed or released +This is actuslly the hesrt of the program. When a button +is not being pressed, nothing is happening (no loops). +This makes the progrsm more battery efficient. +When a setWatch event is raised, the custom callbacks defined +here will be called. These then fired as events to the current +state/screen of the state mschine. +Some events, will result in the stste of the state machine +chsnging, which is why the screen is redrswn after each +button press. +*/ +const setMyWatch = (params) => { + setWatch(() => { + params.bool=!params.bool; + machine = machine.events({object: params.label, status: startEnd(params.bool)}); + drawScreen(machine.screen); + }, params.btn, {repeat:true, edge:"both"}); +}; + +/* object array used to set up the watching functions +*/ +const buttons = [ + {bool : bottom_btn, label : "bottom",btn : BTN3}, + {bool : middle_btn, label : "middle",btn : BTN2}, + {bool : top_btn, label : "top",btn : BTN1}, + {bool : left_btn, label : "left",btn : BTN4}, + {bool : right_btn, label : "right",btn : BTN5} + ]; + +/* set up watchers for buttons */ +for (var button of buttons) + {setMyWatch(button);} + +/* Draw various kinds of buttons */ +const drawButton = (params,side) => { + g.setFontAlign(0,1); + icon = drawIcon(params.primary_icon); + text = params.primary_text; + g.setColor(params.primary_colour); + const x = (side == "left") ? 0 : 120; + if ((params.toggle) && (params.value.value)) { + g.setColor(params.secondary_colour); + text = params.secondary_text; + icon = drawIcon(params.secondary_icon); + } + g.fillRect(0+x,28,119+x, 239); + g.setColor(0x000); + g.setFont("Vector",15); + g.setFontAlign(0,0.0); + g.drawString(text,60+x,160); + options = {rotate: 0, scale:2}; + g.drawImage(icon,x+60,120,options); +}; + +/* Draw the pages corresponding to the states */ +const drawScreen = (params) => { + drawButton(params.left,'left'); + drawButton(params.right,'right'); + g.setColor(0x000); + if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} + if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} + if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} +}; + +machine = Home; // instantiate the state machine at Home +Bangle.drawWidgets(); // draw active widgets +drawScreen(machine.screen); // draw the screen diff --git a/apps/k9control/k9_icon_30.png b/apps/k9control/k9_icon_30.png new file mode 100644 index 0000000000000000000000000000000000000000..f8ecae2b85dc24a11aaa4cb4e0dedba20c92e5cd GIT binary patch literal 4779 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 Z9FxZ=hg`FO|9t`gll|tDyZT2@{R^8<=kNdk literal 0 HcmV?d00001 From 3210548600a749a0847d8fe84ff91f5384ee6ee8 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 21:44:00 +0100 Subject: [PATCH 47/48] Dedicated Dalek Control App --- apps.json | 42 ++- apps/dalekcontrol/README.md | 50 ++++ apps/dalekcontrol/app-icon.js | 1 + apps/dalekcontrol/app.js | 450 ++++++++++++++++++++++++++++ apps/dalekcontrol/dalek_icon_30.png | Bin 0 -> 7042 bytes 5 files changed, 529 insertions(+), 14 deletions(-) create mode 100644 apps/dalekcontrol/README.md create mode 100644 apps/dalekcontrol/app-icon.js create mode 100644 apps/dalekcontrol/app.js create mode 100644 apps/dalekcontrol/dalek_icon_30.png diff --git a/apps.json b/apps.json index 56025ac3d..e5209f601 100644 --- a/apps.json +++ b/apps.json @@ -1785,20 +1785,34 @@ { "name": "BLEcontroller.img", "url": "app-icon.js", "evaluate": true } ] }, - { "id": "k9control", - "name": "K9 BLE Controller with Joystick", - "shortName": "K9 Controller", - "icon": "k9_icon_30.png", - "version": "0.01", - "description": "My private K9 BLE controller", - "tags": "tool,bluetooth", - "readme": "README.md", - "allow_emulator":false, - "storage": [ - { "name": "k9control.app.js", "url": "app.js" }, - { "name": "k9control.img", "url": "app-icon.js", "evaluate": true } - ] - }, + { "id": "k9control", + "name": "K9 BLE Controller with Joystick", + "shortName": "K9 Controller", + "icon": "k9_icon_30.png", + "version": "0.01", + "description": "My private K9 BLE controller", + "tags": "tool,bluetooth", + "readme": "README.md", + "allow_emulator":false, + "storage": [ + { "name": "k9control.app.js", "url": "app.js" }, + { "name": "k9control.img", "url": "app-icon.js", "evaluate": true } + ] + }, + { "id": "dalekcontrol", + "name": "Dalek BLE Controller with Joystick", + "shortName": "Dalek Controller", + "icon": "dalek_icon_30.png", + "version": "0.01", + "description": "My private Dalek BLE controller", + "tags": "tool,bluetooth", + "readme": "README.md", + "allow_emulator":false, + "storage": [ + { "name": "dalekcontrol.app.js", "url": "app.js" }, + { "name": "dalekcontrol.img", "url": "app-icon.js", "evaluate": true } + ] + }, { "id": "widviz", "name": "Widget Visibility Widget", "shortName":"Viz Widget", diff --git a/apps/dalekcontrol/README.md b/apps/dalekcontrol/README.md new file mode 100644 index 000000000..3ffe7f514 --- /dev/null +++ b/apps/dalekcontrol/README.md @@ -0,0 +1,50 @@ +# Dalek Controller + +A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. + +Amaze your friends by controlling your robot, your house or any other BLE device from your watch! + + + +To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: +* message number (up to the least significant four digits) +* screen name (up to four characters) +* object name (up to four characters) +* value/status (up to four characters) + +The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. + +Gordon Williams' EspruinoHub is an excellent way to transform thse BLE advertisements into MQTT messages for further processing. They can be subscribed to via the following MQTT topic (change the watchaddress, to the MAC address of your Bangle.js) +/ble/advertise/wa:tc:ha:dd:re:ss/espruino/# + +## Usage + +The application can be configured at will by changing the definitions of the screens, events, icons and buttons. + +Most changes are possible via data, rather than code change. + +## Features + +The default package contains three configurations: +* a simple home light and sockets controller UI (app.js) +* a robot controller UI with joystick (app-joy.js) +* a simple static assistant controller (app-ex2.js) + +You can try out the other configurations by deleting app.js and renaming the file you want to try as app.js. + +I have tested out the application to as many as eight screens without problems, but four screens are usually enough for most situations. + +## Controls + +The controls will vary by screen, but I suggest a convention of using BTN3 (the bottom button) for moving backwards up the menu stack. + +I have used the convention of red/green for buttons that are switches and blue buttons that provide single function operation (such as navigating a menu or executing a on-off activity) + +## Requests + +In the first instance, please consult my blog post on this application [here](https://k9-build.blogspot.com/2020/05/controlling-k9-using-bluetooth-ble-from.html) + +## Creator + +Richard Hopkins, FIET CEng +May 2020 diff --git a/apps/dalekcontrol/app-icon.js b/apps/dalekcontrol/app-icon.js new file mode 100644 index 000000000..b228e290b --- /dev/null +++ b/apps/dalekcontrol/app-icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("Hh6EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIAAAAAAAAAAAAAAAACIiIiIAAAAAAAACIgAAIiICICIiAAAiIAACIiAiIiAgAgIiIgIiIAAAIgIiIiAAACIiIiAiAAAAAiIiIiAAACIiIiIgAAAAACIiIiAgAAIiIiIAAAAAAiIiIiICIgIiIiIgAAAAAiIiIiIgAiIiIiIgAAAAAiIiIiIiIiIiIiIgAAAAAiACIAAAAAACIAIgAAAAAgAAIAAAAAAAIAAgAAAAIiIiIiIiIiIiIiIiAAAAIiIiIiIiIiIiIiIiAAAAAAAAIAAAAAAAIAAAAAAAIAAAIAAAAAAAIAACAAAAIAAAIAAAAAAAIAACAAACIiIiIiIiIiIiIiIiIAACIAACIAAAAAACIAACIAAAIAAAIAAAAAAAIAACAAACIAACIAAAAAACIAACIAAiIiIiIiIiIiIiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")) diff --git a/apps/dalekcontrol/app.js b/apps/dalekcontrol/app.js new file mode 100644 index 000000000..27e629d5d --- /dev/null +++ b/apps/dalekcontrol/app.js @@ -0,0 +1,450 @@ +/* +========================================================== +Simple event based robot controller that enables robot +to switch into automatic or manual control modes. Behaviours +are controlled via a simple finite state machine. +In automatic mode the +robot will look after itself. In manual mode, the watch +will provide simple forward, back, left and right commands. +The messages will be transmitted to a partner BLE Espruino +using BLE +Written by Richard Hopkins, May 2020 +========================================================== +declare global variables for watch button statuses */ +top_btn = false; +middle_btn = false; +left_btn= false; // the left side of the touch screen +right_btn = false; // the right side of the touch screen +bottom_btn = false; + +msgNum = 0; // message number + +/* +CONFIGURATION AREA - STATE VARIABLES +declare global variables for the toggle button +statuses; if you add an additional toggle button +you should declare it and initiase it here */ + +var status_spk = {value: true}; +var status_face = {value: true}; +var status_iris_light = {value: false}; +var status_iris = {value: false}; +var status_hover = {value: false}; +var status_dome = {value: false}; + +/* trsnsmit message +where +s = first character of state, +o = first three character of object name +v = value of state.object +*/ + +const transmit = (state,object,status) => { + msgNum ++; + msg = { + n: msgNum.toString().slice(-4), + s: state.substr(0,4), + o: object.substr(0,4), + v: status.substr(0,4), + }; + message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; + NRF.setAdvertising({},{ + showName: false, + manufacturer: 0x0590, + manufacturerData: JSON.stringify(message)}); +}; + +/* +CONFIGURATION AREA - ICON DEFINITIONS +Retrieve 30px PNG icons from: +https://icons8.com/icon/set/speak/ios-glyphs +Create icons using: +https://www.espruino.com/Image+Converter +Use compression: true +Transparency: true +Diffusion: flat +Colours: 16bit RGB +Ouput as: Image Object +Add an additional element to the icons array +with a unique name and the data from the Image Object +*/ +const icons = [ + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "spk_on", + data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" + }, + { + name: "spk_off", + data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" + }, + { + name: "facerecog", + data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "happy", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" + }, + { + name: "sad", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" + }, + { + name: "hover", + data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" + }, + { + name: "light", + data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" + }, + { + name: "speak", + data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" + }, + { + name: "dalek", + data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" + } + ]; + +/* finds icon data by name in the icon array and returns an image object*/ +const drawIcon = (name) => { + for (var icon of icons) { + if (icon.name == name) { + image = { + width : 30, height : 30, bpp : 16, + transparent : 1, + buffer: require("heatshrink").decompress(atob(icon.data)) + }; + return image;} + } +}; + +/* +CONFIGURATION AREA - BUTTON DEFINITIONS +for a simple button, just define a primary colour +and an icon name from the icon array and +the text to display beneath the button +for toggle buttons, additionally provide secondary +colours, icon name and text. Also provide a reference +to a global variable for the value of the button. +The global variable should be declared at the start of +the program and it may be adviable to use the 'status_name' +format to ensure it is clear. +*/ + +var happyBtn = { + primary_colour: 0x653E, + primary_text: 'Speak', + primary_icon: 'happy', + }; + +var sadBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'sad', + }; + +var speakBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'speak', + }; + +var faceBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'facerecog', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'facerecog', + value: status_face + }; + +var irisLightBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'light', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'light', + value: status_iris_light + }; + +var irisBtn = { + primary_colour: 0xE9C7, + primary_text: 'Closed', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Open', + secondary_icon : 'awake', + value: status_iris + }; + +var hoverBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'hover', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'hover', + value: status_hover + }; + + var domeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'dalek', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'dalek', + value: status_dome + }; + +/* +CONFIGURATION AREA - SCREEN DEFINITIONS +a screen can have a button (as defined above) +on the left and/or the right of the screen. +in adddition a screen can optionally have +an icon for each of the three buttons on +the left hand side of the screen. These +are defined as btn1, bt2 and bt3. The +values are names from the icon array. +*/ + +const menuScreen = { + left: faceBtn, + right: speakBtn, + btn1: "hover", + btn2: "light", +}; + +const speakScreen = { + left: happyBtn, + right: sadBtn, + btn3: "back" +}; + +const irisScreen = { + left: irisBtn, + right: irisLightBtn, + btn3: "back" +}; + +const lightsScreen = { + left: hoverBtn, + right: domeBtn, + btn3: "back" +}; + +/* base state definition +Each of the screens correspond to a state; +this class provides a constuctor for each +of the states +*/ +class State { + constructor(params) { + this.state = params.state; + this.events = params.events; + this.screen = params.screen; + } +} + +/* +CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS +This area defines how each screen behaves. +Each screen corresponds to a different State of the +state machine. This makes it much easier to isolate +behaviours between screens. +The state value is transmitted whenever a button is pressed +to provide context (so the receiving device, knows which +button was pressed on which screen). +The screens are defined above. +The events section identifies if a particular button has been +pressed and released on the screen and an action can then be taken. +The events function receives a notification from a mySetWatch which +provides an event object that identifies which button and whether +it has been pressed down or released. Actions can then be taken. +The events function will always return a State object. +If the events function returns different State from the current +one, then the state machine will change to that new State and redrsw +the screen appropriately. +To add in additional capabilities for button presses, simply add +an additional 'if' statement. +For toggle buttons, the value of the sppropiate status object is +inversed and the new value transmitted. +*/ + +/* The Home State/Page is where the application beings */ + +const Home = new State({ + state: "DalekMenu", + screen: menuScreen, + events: (event) => { + if ((event.object == "top") && (event.status == "end")) { + return Lights; + } + if ((event.object == "middle") && (event.status == "end")) { + return Iris; + } + if ((event.object == "right") && (event.status == "end")) { + return Speak; + } + if ((event.object == "left") && (event.status == "end")) { + status_face.value = !status_face.value; + transmit(this.state, "face", onOff(status_face.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Speak = new State({ + state: "Speak", + screen: speakScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Iris = new State({ + state: "Iris", + screen: irisScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_iris_light.value = !status_iris_light.value; + transmit(this.state, "light", onOff(status_iris_light.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_iris.value = !status_iris.value; + transmit(this.state, "servo", onOff(status_iris.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Lights = new State({ + state: "Lights", + screen: lightsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_dome.value = !status_dome.value; + transmit(this.state, "dome", onOff(status_dome.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_hover.value = !status_hover.value; + transmit(this.state, "hover", onOff(status_hover.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* translate button status into english */ +const startEnd = status => status ? "start" : "end"; + +/* translate status into english */ +const onOff= status => status ? "on" : "off"; + + +/* create watching functions that will change the global +button status when pressed or released +This is actuslly the hesrt of the program. When a button +is not being pressed, nothing is happening (no loops). +This makes the progrsm more battery efficient. +When a setWatch event is raised, the custom callbacks defined +here will be called. These then fired as events to the current +state/screen of the state mschine. +Some events, will result in the stste of the state machine +chsnging, which is why the screen is redrswn after each +button press. +*/ +const setMyWatch = (params) => { + setWatch(() => { + params.bool=!params.bool; + machine = machine.events({object: params.label, status: startEnd(params.bool)}); + drawScreen(machine.screen); + }, params.btn, {repeat:true, edge:"both"}); +}; + +/* object array used to set up the watching functions +*/ +const buttons = [ + {bool : bottom_btn, label : "bottom",btn : BTN3}, + {bool : middle_btn, label : "middle",btn : BTN2}, + {bool : top_btn, label : "top",btn : BTN1}, + {bool : left_btn, label : "left",btn : BTN4}, + {bool : right_btn, label : "right",btn : BTN5} + ]; + +/* set up watchers for buttons */ +for (var button of buttons) + {setMyWatch(button);} + +/* Draw various kinds of buttons */ +const drawButton = (params,side) => { + g.setFontAlign(0,1); + icon = drawIcon(params.primary_icon); + text = params.primary_text; + g.setColor(params.primary_colour); + const x = (side == "left") ? 0 : 120; + if ((params.toggle) && (params.value.value)) { + g.setColor(params.secondary_colour); + text = params.secondary_text; + icon = drawIcon(params.secondary_icon); + } + g.fillRect(0+x,24,119+x, 239); + g.setColor(0x000); + g.setFont("Vector",15); + g.setFontAlign(0,0.0); + g.drawString(text,60+x,160); + options = {rotate: 0, scale:2}; + g.drawImage(icon,x+60,120,options); +}; + +/* Draw the pages corresponding to the states */ +const drawScreen = (params) => { + drawButton(params.left,'left'); + drawButton(params.right,'right'); + g.setColor(0x000); + if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} + if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} + if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} +}; + +machine = Home; // instantiate the state machine at Home +Bangle.drawWidgets(); // draw active widgets +drawScreen(machine.screen); // draw the screen diff --git a/apps/dalekcontrol/dalek_icon_30.png b/apps/dalekcontrol/dalek_icon_30.png new file mode 100644 index 0000000000000000000000000000000000000000..b59750e9d716d2f67290004367bb3a746f9e6f8d GIT binary patch literal 7042 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 Date: Thu, 11 Jun 2020 15:06:22 +0100 Subject: [PATCH 48/48] revert accidental commits --- .vscode/launch.json | 17 -- apps.json | 30 +- apps/dalekcontrol/README.md | 50 ---- apps/dalekcontrol/app-icon.js | 1 - apps/dalekcontrol/app.js | 450 ---------------------------- apps/dalekcontrol/dalek_icon_30.png | Bin 7042 -> 0 bytes apps/k9control/README.md | 50 ---- apps/k9control/app-icon.js | 1 - apps/k9control/app.js | 446 --------------------------- apps/k9control/k9_icon_30.png | Bin 4779 -> 0 bytes 10 files changed, 1 insertion(+), 1044 deletions(-) delete mode 100644 .vscode/launch.json delete mode 100644 apps/dalekcontrol/README.md delete mode 100644 apps/dalekcontrol/app-icon.js delete mode 100644 apps/dalekcontrol/app.js delete mode 100644 apps/dalekcontrol/dalek_icon_30.png delete mode 100644 apps/k9control/README.md delete mode 100644 apps/k9control/app-icon.js delete mode 100644 apps/k9control/app.js delete mode 100644 apps/k9control/k9_icon_30.png diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 771354e66..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "Launch Program", - "skipFiles": [ - "/**" - ], - "program": "${workspaceFolder}/http-server" - } - ] -} \ No newline at end of file diff --git a/apps.json b/apps.json index 5e4a2b4a5..7aaf66a13 100644 --- a/apps.json +++ b/apps.json @@ -1811,35 +1811,7 @@ { "name": "BLEcontroller.app.js", "url": "app.js" }, { "name": "BLEcontroller.img", "url": "app-icon.js", "evaluate": true } ] - }, - { "id": "k9control", - "name": "K9 BLE Controller with Joystick", - "shortName": "K9 Controller", - "icon": "k9_icon_30.png", - "version": "0.01", - "description": "My private K9 BLE controller", - "tags": "tool,bluetooth", - "readme": "README.md", - "allow_emulator":false, - "storage": [ - { "name": "k9control.app.js", "url": "app.js" }, - { "name": "k9control.img", "url": "app-icon.js", "evaluate": true } - ] - }, - { "id": "dalekcontrol", - "name": "Dalek BLE Controller with Joystick", - "shortName": "Dalek Controller", - "icon": "dalek_icon_30.png", - "version": "0.01", - "description": "My private Dalek BLE controller", - "tags": "tool,bluetooth", - "readme": "README.md", - "allow_emulator":false, - "storage": [ - { "name": "dalekcontrol.app.js", "url": "app.js" }, - { "name": "dalekcontrol.img", "url": "app-icon.js", "evaluate": true } - ] - }, + }, { "id": "widviz", "name": "Widget Visibility Widget", "shortName":"Viz Widget", diff --git a/apps/dalekcontrol/README.md b/apps/dalekcontrol/README.md deleted file mode 100644 index 3ffe7f514..000000000 --- a/apps/dalekcontrol/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# Dalek Controller - -A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. - -Amaze your friends by controlling your robot, your house or any other BLE device from your watch! - - - -To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: -* message number (up to the least significant four digits) -* screen name (up to four characters) -* object name (up to four characters) -* value/status (up to four characters) - -The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. - -Gordon Williams' EspruinoHub is an excellent way to transform thse BLE advertisements into MQTT messages for further processing. They can be subscribed to via the following MQTT topic (change the watchaddress, to the MAC address of your Bangle.js) -/ble/advertise/wa:tc:ha:dd:re:ss/espruino/# - -## Usage - -The application can be configured at will by changing the definitions of the screens, events, icons and buttons. - -Most changes are possible via data, rather than code change. - -## Features - -The default package contains three configurations: -* a simple home light and sockets controller UI (app.js) -* a robot controller UI with joystick (app-joy.js) -* a simple static assistant controller (app-ex2.js) - -You can try out the other configurations by deleting app.js and renaming the file you want to try as app.js. - -I have tested out the application to as many as eight screens without problems, but four screens are usually enough for most situations. - -## Controls - -The controls will vary by screen, but I suggest a convention of using BTN3 (the bottom button) for moving backwards up the menu stack. - -I have used the convention of red/green for buttons that are switches and blue buttons that provide single function operation (such as navigating a menu or executing a on-off activity) - -## Requests - -In the first instance, please consult my blog post on this application [here](https://k9-build.blogspot.com/2020/05/controlling-k9-using-bluetooth-ble-from.html) - -## Creator - -Richard Hopkins, FIET CEng -May 2020 diff --git a/apps/dalekcontrol/app-icon.js b/apps/dalekcontrol/app-icon.js deleted file mode 100644 index b228e290b..000000000 --- a/apps/dalekcontrol/app-icon.js +++ /dev/null @@ -1 +0,0 @@ -E.toArrayBuffer(atob("Hh6EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIAAAAAAAAAAAAAAAACIiIiIAAAAAAAACIgAAIiICICIiAAAiIAACIiAiIiAgAgIiIgIiIAAAIgIiIiAAACIiIiAiAAAAAiIiIiAAACIiIiIgAAAAACIiIiAgAAIiIiIAAAAAAiIiIiICIgIiIiIgAAAAAiIiIiIgAiIiIiIgAAAAAiIiIiIiIiIiIiIgAAAAAiACIAAAAAACIAIgAAAAAgAAIAAAAAAAIAAgAAAAIiIiIiIiIiIiIiIiAAAAIiIiIiIiIiIiIiIiAAAAAAAAIAAAAAAAIAAAAAAAIAAAIAAAAAAAIAACAAAAIAAAIAAAAAAAIAACAAACIiIiIiIiIiIiIiIiIAACIAACIAAAAAACIAACIAAAIAAAIAAAAAAAIAACAAACIAACIAAAAAACIAACIAAiIiIiIiIiIiIiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")) diff --git a/apps/dalekcontrol/app.js b/apps/dalekcontrol/app.js deleted file mode 100644 index 27e629d5d..000000000 --- a/apps/dalekcontrol/app.js +++ /dev/null @@ -1,450 +0,0 @@ -/* -========================================================== -Simple event based robot controller that enables robot -to switch into automatic or manual control modes. Behaviours -are controlled via a simple finite state machine. -In automatic mode the -robot will look after itself. In manual mode, the watch -will provide simple forward, back, left and right commands. -The messages will be transmitted to a partner BLE Espruino -using BLE -Written by Richard Hopkins, May 2020 -========================================================== -declare global variables for watch button statuses */ -top_btn = false; -middle_btn = false; -left_btn= false; // the left side of the touch screen -right_btn = false; // the right side of the touch screen -bottom_btn = false; - -msgNum = 0; // message number - -/* -CONFIGURATION AREA - STATE VARIABLES -declare global variables for the toggle button -statuses; if you add an additional toggle button -you should declare it and initiase it here */ - -var status_spk = {value: true}; -var status_face = {value: true}; -var status_iris_light = {value: false}; -var status_iris = {value: false}; -var status_hover = {value: false}; -var status_dome = {value: false}; - -/* trsnsmit message -where -s = first character of state, -o = first three character of object name -v = value of state.object -*/ - -const transmit = (state,object,status) => { - msgNum ++; - msg = { - n: msgNum.toString().slice(-4), - s: state.substr(0,4), - o: object.substr(0,4), - v: status.substr(0,4), - }; - message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; - NRF.setAdvertising({},{ - showName: false, - manufacturer: 0x0590, - manufacturerData: JSON.stringify(message)}); -}; - -/* -CONFIGURATION AREA - ICON DEFINITIONS -Retrieve 30px PNG icons from: -https://icons8.com/icon/set/speak/ios-glyphs -Create icons using: -https://www.espruino.com/Image+Converter -Use compression: true -Transparency: true -Diffusion: flat -Colours: 16bit RGB -Ouput as: Image Object -Add an additional element to the icons array -with a unique name and the data from the Image Object -*/ -const icons = [ - { - name: "back", - data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" - }, - { - name: "spk_on", - data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" - }, - { - name: "spk_off", - data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" - }, - { - name: "facerecog", - data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" - }, - { - name: "sleep", - data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" - }, - { - name: "awake", - data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" - }, - { - name: "happy", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" - }, - { - name: "sad", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" - }, - { - name: "hover", - data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" - }, - { - name: "light", - data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" - }, - { - name: "speak", - data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" - }, - { - name: "dalek", - data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" - } - ]; - -/* finds icon data by name in the icon array and returns an image object*/ -const drawIcon = (name) => { - for (var icon of icons) { - if (icon.name == name) { - image = { - width : 30, height : 30, bpp : 16, - transparent : 1, - buffer: require("heatshrink").decompress(atob(icon.data)) - }; - return image;} - } -}; - -/* -CONFIGURATION AREA - BUTTON DEFINITIONS -for a simple button, just define a primary colour -and an icon name from the icon array and -the text to display beneath the button -for toggle buttons, additionally provide secondary -colours, icon name and text. Also provide a reference -to a global variable for the value of the button. -The global variable should be declared at the start of -the program and it may be adviable to use the 'status_name' -format to ensure it is clear. -*/ - -var happyBtn = { - primary_colour: 0x653E, - primary_text: 'Speak', - primary_icon: 'happy', - }; - -var sadBtn = { - primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'sad', - }; - -var speakBtn = { - primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'speak', - }; - -var faceBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'facerecog', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'facerecog', - value: status_face - }; - -var irisLightBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'light', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'light', - value: status_iris_light - }; - -var irisBtn = { - primary_colour: 0xE9C7, - primary_text: 'Closed', - primary_icon: 'sleep', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Open', - secondary_icon : 'awake', - value: status_iris - }; - -var hoverBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'hover', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'hover', - value: status_hover - }; - - var domeBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'dalek', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'dalek', - value: status_dome - }; - -/* -CONFIGURATION AREA - SCREEN DEFINITIONS -a screen can have a button (as defined above) -on the left and/or the right of the screen. -in adddition a screen can optionally have -an icon for each of the three buttons on -the left hand side of the screen. These -are defined as btn1, bt2 and bt3. The -values are names from the icon array. -*/ - -const menuScreen = { - left: faceBtn, - right: speakBtn, - btn1: "hover", - btn2: "light", -}; - -const speakScreen = { - left: happyBtn, - right: sadBtn, - btn3: "back" -}; - -const irisScreen = { - left: irisBtn, - right: irisLightBtn, - btn3: "back" -}; - -const lightsScreen = { - left: hoverBtn, - right: domeBtn, - btn3: "back" -}; - -/* base state definition -Each of the screens correspond to a state; -this class provides a constuctor for each -of the states -*/ -class State { - constructor(params) { - this.state = params.state; - this.events = params.events; - this.screen = params.screen; - } -} - -/* -CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS -This area defines how each screen behaves. -Each screen corresponds to a different State of the -state machine. This makes it much easier to isolate -behaviours between screens. -The state value is transmitted whenever a button is pressed -to provide context (so the receiving device, knows which -button was pressed on which screen). -The screens are defined above. -The events section identifies if a particular button has been -pressed and released on the screen and an action can then be taken. -The events function receives a notification from a mySetWatch which -provides an event object that identifies which button and whether -it has been pressed down or released. Actions can then be taken. -The events function will always return a State object. -If the events function returns different State from the current -one, then the state machine will change to that new State and redrsw -the screen appropriately. -To add in additional capabilities for button presses, simply add -an additional 'if' statement. -For toggle buttons, the value of the sppropiate status object is -inversed and the new value transmitted. -*/ - -/* The Home State/Page is where the application beings */ - -const Home = new State({ - state: "DalekMenu", - screen: menuScreen, - events: (event) => { - if ((event.object == "top") && (event.status == "end")) { - return Lights; - } - if ((event.object == "middle") && (event.status == "end")) { - return Iris; - } - if ((event.object == "right") && (event.status == "end")) { - return Speak; - } - if ((event.object == "left") && (event.status == "end")) { - status_face.value = !status_face.value; - transmit(this.state, "face", onOff(status_face.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Speak = new State({ - state: "Speak", - screen: speakScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Iris = new State({ - state: "Iris", - screen: irisScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_iris_light.value = !status_iris_light.value; - transmit(this.state, "light", onOff(status_iris_light.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_iris.value = !status_iris.value; - transmit(this.state, "servo", onOff(status_iris.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Lights = new State({ - state: "Lights", - screen: lightsScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_dome.value = !status_dome.value; - transmit(this.state, "dome", onOff(status_dome.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_hover.value = !status_hover.value; - transmit(this.state, "hover", onOff(status_hover.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -/* translate button status into english */ -const startEnd = status => status ? "start" : "end"; - -/* translate status into english */ -const onOff= status => status ? "on" : "off"; - - -/* create watching functions that will change the global -button status when pressed or released -This is actuslly the hesrt of the program. When a button -is not being pressed, nothing is happening (no loops). -This makes the progrsm more battery efficient. -When a setWatch event is raised, the custom callbacks defined -here will be called. These then fired as events to the current -state/screen of the state mschine. -Some events, will result in the stste of the state machine -chsnging, which is why the screen is redrswn after each -button press. -*/ -const setMyWatch = (params) => { - setWatch(() => { - params.bool=!params.bool; - machine = machine.events({object: params.label, status: startEnd(params.bool)}); - drawScreen(machine.screen); - }, params.btn, {repeat:true, edge:"both"}); -}; - -/* object array used to set up the watching functions -*/ -const buttons = [ - {bool : bottom_btn, label : "bottom",btn : BTN3}, - {bool : middle_btn, label : "middle",btn : BTN2}, - {bool : top_btn, label : "top",btn : BTN1}, - {bool : left_btn, label : "left",btn : BTN4}, - {bool : right_btn, label : "right",btn : BTN5} - ]; - -/* set up watchers for buttons */ -for (var button of buttons) - {setMyWatch(button);} - -/* Draw various kinds of buttons */ -const drawButton = (params,side) => { - g.setFontAlign(0,1); - icon = drawIcon(params.primary_icon); - text = params.primary_text; - g.setColor(params.primary_colour); - const x = (side == "left") ? 0 : 120; - if ((params.toggle) && (params.value.value)) { - g.setColor(params.secondary_colour); - text = params.secondary_text; - icon = drawIcon(params.secondary_icon); - } - g.fillRect(0+x,24,119+x, 239); - g.setColor(0x000); - g.setFont("Vector",15); - g.setFontAlign(0,0.0); - g.drawString(text,60+x,160); - options = {rotate: 0, scale:2}; - g.drawImage(icon,x+60,120,options); -}; - -/* Draw the pages corresponding to the states */ -const drawScreen = (params) => { - drawButton(params.left,'left'); - drawButton(params.right,'right'); - g.setColor(0x000); - if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} - if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} - if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} -}; - -machine = Home; // instantiate the state machine at Home -Bangle.drawWidgets(); // draw active widgets -drawScreen(machine.screen); // draw the screen diff --git a/apps/dalekcontrol/dalek_icon_30.png b/apps/dalekcontrol/dalek_icon_30.png deleted file mode 100644 index b59750e9d716d2f67290004367bb3a746f9e6f8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7042 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 - -To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: -* message number (up to the least significant four digits) -* screen name (up to four characters) -* object name (up to four characters) -* value/status (up to four characters) - -The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. - -Gordon Williams' EspruinoHub is an excellent way to transform thse BLE advertisements into MQTT messages for further processing. They can be subscribed to via the following MQTT topic (change the watchaddress, to the MAC address of your Bangle.js) -/ble/advertise/wa:tc:ha:dd:re:ss/espruino/# - -## Usage - -The application can be configured at will by changing the definitions of the screens, events, icons and buttons. - -Most changes are possible via data, rather than code change. - -## Features - -The default package contains three configurations: -* a simple home light and sockets controller UI (app.js) -* a robot controller UI with joystick (app-joy.js) -* a simple static assistant controller (app-ex2.js) - -You can try out the other configurations by deleting app.js and renaming the file you want to try as app.js. - -I have tested out the application to as many as eight screens without problems, but four screens are usually enough for most situations. - -## Controls - -The controls will vary by screen, but I suggest a convention of using BTN3 (the bottom button) for moving backwards up the menu stack. - -I have used the convention of red/green for buttons that are switches and blue buttons that provide single function operation (such as navigating a menu or executing a on-off activity) - -## Requests - -In the first instance, please consult my blog post on this application [here](https://k9-build.blogspot.com/2020/05/controlling-k9-using-bluetooth-ble-from.html) - -## Creator - -Richard Hopkins, FIET CEng -May 2020 diff --git a/apps/k9control/app-icon.js b/apps/k9control/app-icon.js deleted file mode 100644 index 55d7fb3cc..000000000 --- a/apps/k9control/app-icon.js +++ /dev/null @@ -1 +0,0 @@ -E.toArrayBuffer(atob("JyeEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiAAAAAAAAAAAAAAAAAAAAAAAAAiAAAAAAAAAAAAAAAAAAAAACIiIiAAAAAAAAAAAAAAAAAAAAACIiIgAAAAIAAAAAAAAAAAAAAAAiIiIiIAAAAiAAAAAAAAAAAAAAAiIiIiIAAAACIiAAAAAAAAAAAAAiIiIiIAAAAAAiIgAAAiIiIiIgAiIiIiIiAAAAAAIiIiIiIiIiIiIiIiIiIiIAAAAAACIiIiIiIiIiIiIiIiIiIgAAAAAAIiIiIiIiIiIiIiIiIiIiAAAAAAIiIiIiIiIiIiIgAiIiIgAAAAACIiIiIiIiIiIiIAACIiIAAAAAAiIiIiIiIiIiIiAAAAAAAAAAAAIiIiIiIiIiIiIiAAAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAAiIiIiIiIiIiIiIiAAAAAAAAAAAiIiIiIiIiIiIiIiIAAAAAAAAAAiIiIiIiIiIiIiIiIAAAAAAAAAIiIiIiIiIiIiIiIiIAAAAAAAAAIiIiIiIiIiIiIiIiIgAAAAAAACIiIiIiIiIiIiIiIiIgAAAAAAACIiIiIiIiIiIiIiIiIiAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")) diff --git a/apps/k9control/app.js b/apps/k9control/app.js deleted file mode 100644 index 0735aeee6..000000000 --- a/apps/k9control/app.js +++ /dev/null @@ -1,446 +0,0 @@ -/* -========================================================== -Simple event based robot controller that enables robot -to switch into automatic or manual control modes. Behaviours -are controlled via a simple finite state machine. -In automatic mode the -robot will look after itself. In manual mode, the watch -will provide simple forward, back, left and right commands. -The messages will be transmitted to a partner BLE Espruino -using BLE -Written by Richard Hopkins, May 2020 -========================================================== -declare global variables for watch button statuses */ -top_btn = false; -middle_btn = false; -left_btn= false; // the left side of the touch screen -right_btn = false; // the right side of the touch screen -bottom_btn = false; - -msgNum = 0; // message number - -NRF.setConnectionInterval(100); -Bangle.loadWidgets(); -Bangle.drawWidgets(); -/* -CONFIGURATION AREA - STATE VARIABLES -declare global variables for the toggle button -statuses; if you add an additional toggle button -you should declare it and initiase it here */ - -var status_auto = {value: false}; -var status_chess = {value: false}; -var status_wake = {value: false}; - -/* trsnsmit message -where -s = first character of state, -o = first three character of object name -v = value of state.object -*/ - -const transmit = (state,object,status) => { - msgNum ++; - msg = { - n: msgNum.toString().slice(-4), - s: state.substr(0,4), - o: object.substr(0,4), - v: status.substr(0,4), - }; - message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; - NRF.setAdvertising({},{ - showName: false, - manufacturer: 0x0590, - manufacturerData: JSON.stringify(message)}); -}; - -/* -CONFIGURATION AREA - ICON DEFINITIONS -Retrieve 30px PNG icons from: -https://icons8.com/icon/set/speak/ios-glyphs -Create icons using: -https://www.espruino.com/Image+Converter -Use compression: true -Transparency: true -Diffusion: flat -Colours: 16bit RGB -Ouput as: Image Object -Add an additional element to the icons array -with a unique name and the data from the Image Object -*/ -const icons = [ - { - name: "walk", - data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" - }, - { - name: "sit", - data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" - }, - { - name: "joystick", - data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" - }, - { - name: "left", - data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" - }, - { - name: "right", - data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" - }, - { - name: "forward", - data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" - }, - { - name: "backward", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" - }, - { - name: "back", - data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" - }, - { - name: "mic_on", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" - }, - { - name: "comms", - data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" - }, - { - name: "pawn", - data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" - }, - { - name: "sleep", - data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" - }, - { - name: "awake", - data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" - }, - { - name: "wag_h", - data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" - }, - { - name: "wag_v", - data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" - } - ]; - -/* finds icon data by name in the icon array and returns an image object*/ -const drawIcon = (name) => { - for (var icon of icons) { - if (icon.name == name) { - image = { - width : 30, height : 30, bpp : 16, - transparent : 1, - buffer: require("heatshrink").decompress(atob(icon.data)) - }; - return image;} - } -}; - -/* -CONFIGURATION AREA - BUTTON DEFINITIONS -for a simple button, just define a primary colour -and an icon name from the icon array and -the text to display beneath the button -for toggle buttons, additionally provide secondary -colours, icon name and text. Also provide a reference -to a global variable for the value of the button. -The global variable should be declared at the start of -the program and it may be adviable to use the 'status_name' -format to ensure it is clear. -*/ - -var joystickBtn = { - primary_colour: 0x653E, - primary_icon: 'joystick', - primary_text: 'Joystick', - }; - -var turnLeftBtn = { - primary_colour: 0x653E, - primary_text: 'Left', - primary_icon: 'left', - }; - -var turnRightBtn = { - primary_colour: 0x33F9, - primary_text: 'Right', - primary_icon: 'right', - }; - -var tailHBtn = { - primary_colour: 0x653E, - primary_text: 'Wag Tail', - primary_icon: 'wag_h', - }; - -var tailVBtn = { - primary_colour: 0x33F9, - primary_text: 'Wag Tail', - primary_icon: 'wag_v', - }; - -var chessBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'pawn', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'pawn', - value: status_chess - }; - -var wakeBtn = { - primary_colour: 0xE9C7, - primary_text: 'Sleeping', - primary_icon: 'sleep', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Awake', - secondary_icon : 'awake', - value: status_wake - }; - -var autoBtn = { - primary_colour: 0xE9C7, - primary_text: 'Stop', - primary_icon: 'sit', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Move', - secondary_icon : 'walk', - value: status_auto - }; - -/* -CONFIGURATION AREA - SCREEN DEFINITIONS -a screen can have a button (as defined above) -on the left and/or the right of the screen. -in adddition a screen can optionally have -an icon for each of the three buttons on -the left hand side of the screen. These -are defined as btn1, bt2 and bt3. The -values are names from the icon array. -*/ -const menuScreen = { - left: wakeBtn, - right: joystickBtn, - btn1: "pawn", - btn2: "wag_v", -}; - -const joystickScreen = { - left: turnLeftBtn, - right: turnRightBtn, - btn1: "forward", - btn2: "backward", - btn3: "back" -}; - -const tailScreen = { - left: tailHBtn, - right: tailVBtn, - btn3: "back" -}; - -const chessScreen = { - left: chessBtn, - right: autoBtn, - btn3: "back" -}; - - -/* base state definition -Each of the screens correspond to a state; -this class provides a constuctor for each -of the states -*/ -class State { - constructor(params) { - this.state = params.state; - this.events = params.events; - this.screen = params.screen; - } -} - -/* -CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS -This area defines how each screen behaves. -Each screen corresponds to a different State of the -state machine. This makes it much easier to isolate -behaviours between screens. -The state value is transmitted whenever a button is pressed -to provide context (so the receiving device, knows which -button was pressed on which screen). -The screens are defined above. -The events section identifies if a particular button has been -pressed and released on the screen and an action can then be taken. -The events function receives a notification from a mySetWatch which -provides an event object that identifies which button and whether -it has been pressed down or released. Actions can then be taken. -The events function will always return a State object. -If the events function returns different State from the current -one, then the state machine will change to that new State and redrsw -the screen appropriately. -To add in additional capabilities for button presses, simply add -an additional 'if' statement. -For toggle buttons, the value of the appropiate status object is -inversed and the new value transmitted. -*/ - -/* The Home State/Page is where the application beings */ - -const Home = new State({ - state: "K9Menu", - screen: menuScreen, - events: (event) => { - if ((event.object == "top") && (event.status == "end")) { - return Chess; - } - if ((event.object == "middle") && (event.status == "end")) { - return Tail; - } - if ((event.object == "right") && (event.status == "end")) { - return Joystick; - } - if ((event.object == "left") && (event.status == "end")) { - status_wake.value = !status_wake.value; - transmit(this.state, "wake", onOff(status_wake.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Chess = new State({ - state: "Chess", - screen: chessScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_auto.value = !status_auto.value; - transmit(this.state, "follow", onOff(status_auto.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_chess.value = !status_chess.value; - transmit(this.state, "chess", onOff(status_chess.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Tail = new State({ - state: "Tail", - screen: tailScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -/* Joystick page state */ -const Joystick = new State({ - state: "Joystick", - screen: joystickScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - transmit("Joystick", "joystick", "off"); - return Home; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -/* translate button status into english */ -const startEnd = status => status ? "start" : "end"; - -/* translate status into english */ -const onOff= status => status ? "on" : "off"; - - -/* create watching functions that will change the global -button status when pressed or released -This is actuslly the hesrt of the program. When a button -is not being pressed, nothing is happening (no loops). -This makes the progrsm more battery efficient. -When a setWatch event is raised, the custom callbacks defined -here will be called. These then fired as events to the current -state/screen of the state mschine. -Some events, will result in the stste of the state machine -chsnging, which is why the screen is redrswn after each -button press. -*/ -const setMyWatch = (params) => { - setWatch(() => { - params.bool=!params.bool; - machine = machine.events({object: params.label, status: startEnd(params.bool)}); - drawScreen(machine.screen); - }, params.btn, {repeat:true, edge:"both"}); -}; - -/* object array used to set up the watching functions -*/ -const buttons = [ - {bool : bottom_btn, label : "bottom",btn : BTN3}, - {bool : middle_btn, label : "middle",btn : BTN2}, - {bool : top_btn, label : "top",btn : BTN1}, - {bool : left_btn, label : "left",btn : BTN4}, - {bool : right_btn, label : "right",btn : BTN5} - ]; - -/* set up watchers for buttons */ -for (var button of buttons) - {setMyWatch(button);} - -/* Draw various kinds of buttons */ -const drawButton = (params,side) => { - g.setFontAlign(0,1); - icon = drawIcon(params.primary_icon); - text = params.primary_text; - g.setColor(params.primary_colour); - const x = (side == "left") ? 0 : 120; - if ((params.toggle) && (params.value.value)) { - g.setColor(params.secondary_colour); - text = params.secondary_text; - icon = drawIcon(params.secondary_icon); - } - g.fillRect(0+x,28,119+x, 239); - g.setColor(0x000); - g.setFont("Vector",15); - g.setFontAlign(0,0.0); - g.drawString(text,60+x,160); - options = {rotate: 0, scale:2}; - g.drawImage(icon,x+60,120,options); -}; - -/* Draw the pages corresponding to the states */ -const drawScreen = (params) => { - drawButton(params.left,'left'); - drawButton(params.right,'right'); - g.setColor(0x000); - if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} - if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} - if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} -}; - -machine = Home; // instantiate the state machine at Home -Bangle.drawWidgets(); // draw active widgets -drawScreen(machine.screen); // draw the screen diff --git a/apps/k9control/k9_icon_30.png b/apps/k9control/k9_icon_30.png deleted file mode 100644 index f8ecae2b85dc24a11aaa4cb4e0dedba20c92e5cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4779 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 Z9FxZ=hg`FO|9t`gll|tDyZT2@{R^8<=kNdk