Merge branch 'master' into release/largeclock
commit
cdfeaf6f61
40
apps.json
40
apps.json
|
|
@ -1283,7 +1283,7 @@
|
||||||
"name": "Numerals Clock",
|
"name": "Numerals Clock",
|
||||||
"shortName": "Numerals Clock",
|
"shortName": "Numerals Clock",
|
||||||
"icon": "numerals.png",
|
"icon": "numerals.png",
|
||||||
"version":"0.04",
|
"version":"0.05",
|
||||||
"description": "A simple big numerals clock",
|
"description": "A simple big numerals clock",
|
||||||
"tags": "numerals,clock",
|
"tags": "numerals,clock",
|
||||||
"type":"clock",
|
"type":"clock",
|
||||||
|
|
@ -1578,6 +1578,44 @@
|
||||||
{
|
{
|
||||||
"name": "largeclock.json",
|
"name": "largeclock.json",
|
||||||
"url": "largeclock.json",
|
"url": "largeclock.json",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ "id": "smtswch",
|
||||||
|
"name": "Smart Switch",
|
||||||
|
"shortName":"Smart Switch",
|
||||||
|
"icon": "app.png",
|
||||||
|
"version":"0.01",
|
||||||
|
"description": "Using EspruinoHub, control your smart devices on and off via Bluetooth Low Energy!",
|
||||||
|
"tags": "bluetooth,btle,smart,switch",
|
||||||
|
"type": "app",
|
||||||
|
"readme": "README.md",
|
||||||
|
"storage": [
|
||||||
|
{"name":"smtswch.app.js","url":"app.js"},
|
||||||
|
{"name":"smtswch.img","url":"app-icon.js","evaluate":true},
|
||||||
|
{"name":"light-on.img","url":"light-on.js","evaluate":true},
|
||||||
|
{"name":"light-off.img","url":"light-off.js","evaluate":true},
|
||||||
|
{"name":"switch-on.img","url":"switch-on.js","evaluate":true},
|
||||||
|
{"name":"switch-off.img","url":"switch-off.js","evaluate":true}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "simpletimer",
|
||||||
|
"name": "Timer",
|
||||||
|
"icon": "app.png",
|
||||||
|
"version": "0.01",
|
||||||
|
"description": "Simple timer, useful when playing board games or cooking",
|
||||||
|
"tags": "timer",
|
||||||
|
"readme": "README.md",
|
||||||
|
"allow_emulator": true,
|
||||||
|
"storage": [
|
||||||
|
{
|
||||||
|
"name": "simpletimer.app.js",
|
||||||
|
"url": "app.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "simpletimer.img",
|
||||||
|
"url": "app-icon.js",
|
||||||
"evaluate": true
|
"evaluate": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,4 @@
|
||||||
0.02: Use BTN2 for settings menu like other clocks
|
0.02: Use BTN2 for settings menu like other clocks
|
||||||
0.03: maximize numerals, make menu button configurable, change icon to mac palette, add default settings file, respect 12hour setting
|
0.03: maximize numerals, make menu button configurable, change icon to mac palette, add default settings file, respect 12hour setting
|
||||||
0.04: Don't overwrite existing settings on app update
|
0.04: Don't overwrite existing settings on app update
|
||||||
|
0.05: Fix settings issue
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
}
|
}
|
||||||
let numeralsSettings = storage.readJSON('numerals.json',1);
|
let numeralsSettings = storage.readJSON('numerals.json',1);
|
||||||
if (!numeralsSettings) resetSettings();
|
if (!numeralsSettings) resetSettings();
|
||||||
|
if (numeralsSettings.menuButton===undefined) numeralsSettings.menuButton=22;
|
||||||
let dm = ["fill","frame"];
|
let dm = ["fill","frame"];
|
||||||
let col = ["rnd","r/g","y/w","o/c","b/y"];
|
let col = ["rnd","r/g","y/w","o/c","b/y"];
|
||||||
let btn = [[24,"BTN1"],[22,"BTN2"],[23,"BTN3"],[11,"BTN4"],[16,"BTN5"]];
|
let btn = [[24,"BTN1"],[22,"BTN2"],[23,"BTN3"],[11,"BTN4"],[16,"BTN5"]];
|
||||||
|
|
@ -30,7 +31,7 @@
|
||||||
onchange: v=> { numeralsSettings.drawMode=dm[v]; updateSettings();}
|
onchange: v=> { numeralsSettings.drawMode=dm[v]; updateSettings();}
|
||||||
},
|
},
|
||||||
"Menu button": {
|
"Menu button": {
|
||||||
value: 1|btn[numeralsSettings.menuButton],
|
value: btn.findIndex(e=>e[0]==numeralsSettings.menuButton),
|
||||||
min:0,max:4,
|
min:0,max:4,
|
||||||
format: v=>btn[v][1],
|
format: v=>btn[v][1],
|
||||||
onchange: v=> { numeralsSettings.menuButton=btn[v][0]; updateSettings();}
|
onchange: v=> { numeralsSettings.menuButton=btn[v][0]; updateSettings();}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: Initial version
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Timer
|
||||||
|
|
||||||
|
Simple timer, useful when playing board games or cooking
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- When the time is up the timer can be reset to starting time, this is useful e.g. for playing board games
|
||||||
|
- When the countdown is running the timer cannot be adjusted, this prevents accidental time variations
|
||||||
|
- When the time is up the starting time is shown, as a reminder of the time elapsed
|
||||||
|
|
||||||
|
## How to use it
|
||||||
|
|
||||||
|
- Tap on minutes to increase them one by one
|
||||||
|
- Tap on seconds to increase them one by one
|
||||||
|
- Press BTN3 to reset time to 0
|
||||||
|
- Press BTN1 to start the timer or reset to the original time
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
require("heatshrink").decompress(
|
||||||
|
atob(
|
||||||
|
"mEwxH+AH4A/AEsxAAQso1eyrgvDrmrw4skAAQuDAAIHBrYABFsQvMGLYtGAAOAFweA2WrF4gwYFxAwEFwIvBwowFsIub64AB6wJF6wJB1mGMTFbrmsEYoADHAwAC1dhGCoTCmJhBEYoAM2RiFF6VbleBF6QABGAguSw2sgAwnCAdhXYIwBqwvT2WFDwYvP1YZCwMAlYwT1ZgORogZEqwwB1iRhBoYmGlcAYiZgOBgWFDIzCBAALESYIYvMw4ZHGCuHF5aOKeYgABYiCQMBYeyDZLzBAAQwO2QvPDhbzCeqAvbGAQQBlYvqeYIvteYMreJ7vaACbvQJxwAP1YvLGAeHF7uHFxYvDwovdwovPSDusRxgvEwwvbwwvNGAmrds4vGsOyFy+ysIvPSLqNPGDwuT/xyEwySS2QuEF6BgEYYL0Q1ZIEFyIwGMQIxM1ZcFFyYwHreFw+rSwmy1eHwoSGFygxJABwtXeo4upMSQtdGZorjAH4A/AF4A=="
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
let counter = 0;
|
||||||
|
let setValue = 0;
|
||||||
|
let counterInterval;
|
||||||
|
let state;
|
||||||
|
|
||||||
|
const DEBOUNCE = 50;
|
||||||
|
|
||||||
|
function buzzAndBeep() {
|
||||||
|
return Bangle.buzz(1000, 1)
|
||||||
|
.then(() => Bangle.beep(200, 3000))
|
||||||
|
.then(() => setTimeout(buzzAndBeep, 5000));
|
||||||
|
}
|
||||||
|
|
||||||
|
function outOfTime() {
|
||||||
|
g.clearRect(0, 0, 220, 70);
|
||||||
|
g.setFontAlign(0, 0);
|
||||||
|
g.setFont("6x8", 3);
|
||||||
|
g.drawString("Time UP!", 120, 50);
|
||||||
|
counter = setValue;
|
||||||
|
buzzAndBeep();
|
||||||
|
setInterval(() => {
|
||||||
|
g.clearRect(0, 70, 220, 160);
|
||||||
|
setTimeout(draw, 200);
|
||||||
|
}, 400);
|
||||||
|
state = "stopped";
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
const minutes = Math.floor(counter / 60);
|
||||||
|
const seconds = Math.floor(counter % 60);
|
||||||
|
const seconds2Digits = seconds < 10 ? `0${seconds}` : seconds.toString();
|
||||||
|
g.clearRect(0, 70, 220, 160);
|
||||||
|
g.setFontAlign(0, 0);
|
||||||
|
g.setFont("6x8", 7);
|
||||||
|
g.drawString(
|
||||||
|
`${minutes < 10 ? "0" : ""}${minutes}:${seconds2Digits}`,
|
||||||
|
120,
|
||||||
|
120
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function countDown() {
|
||||||
|
if (counter <= 0) {
|
||||||
|
if (counterInterval) {
|
||||||
|
clearInterval(counterInterval);
|
||||||
|
counterInterval = undefined;
|
||||||
|
}
|
||||||
|
outOfTime();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
counter--;
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearIntervals() {
|
||||||
|
clearInterval();
|
||||||
|
counterInterval = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function set(delta) {
|
||||||
|
if (state === "started") return;
|
||||||
|
counter += delta;
|
||||||
|
if (state === "unset") {
|
||||||
|
state = "set";
|
||||||
|
}
|
||||||
|
draw();
|
||||||
|
g.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
function startTimer() {
|
||||||
|
setValue = counter;
|
||||||
|
countDown();
|
||||||
|
counterInterval = setInterval(countDown, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unset -> set -> started -> -> stopped -> set
|
||||||
|
const stateMap = {
|
||||||
|
set: () => {
|
||||||
|
state = "started";
|
||||||
|
startTimer();
|
||||||
|
},
|
||||||
|
started: () => {
|
||||||
|
reset(setValue);
|
||||||
|
},
|
||||||
|
stopped: () => {
|
||||||
|
reset(setValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function changeState() {
|
||||||
|
if (stateMap[state]) stateMap[state]();
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawLabels() {
|
||||||
|
g.clear();
|
||||||
|
g.setFontAlign(-1, 0);
|
||||||
|
g.setFont("6x8", 7);
|
||||||
|
g.drawString(`+ +`, 35, 180);
|
||||||
|
g.setFontAlign(0, 0, 3);
|
||||||
|
g.setFont("6x8", 1);
|
||||||
|
g.drawString(`reset (re)start`, 230, 120);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset(value) {
|
||||||
|
clearIntervals();
|
||||||
|
counter = value;
|
||||||
|
setValue = value;
|
||||||
|
drawLabels();
|
||||||
|
draw();
|
||||||
|
state = value === 0 ? "unset" : "set";
|
||||||
|
}
|
||||||
|
|
||||||
|
function addWatch() {
|
||||||
|
clearWatch();
|
||||||
|
setWatch(changeState, BTN1, {
|
||||||
|
debounce: DEBOUNCE,
|
||||||
|
repeat: true,
|
||||||
|
edge: "falling"
|
||||||
|
});
|
||||||
|
setWatch(
|
||||||
|
() => {
|
||||||
|
reset(0);
|
||||||
|
},
|
||||||
|
BTN3,
|
||||||
|
{
|
||||||
|
debounce: DEBOUNCE,
|
||||||
|
repeat: true,
|
||||||
|
edge: "falling"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
setWatch(
|
||||||
|
() => {
|
||||||
|
set(60);
|
||||||
|
},
|
||||||
|
BTN4,
|
||||||
|
{
|
||||||
|
debounce: DEBOUNCE,
|
||||||
|
repeat: true,
|
||||||
|
edge: "falling"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
setWatch(() => set(1), BTN5, {
|
||||||
|
debounce: DEBOUNCE,
|
||||||
|
repeat: true,
|
||||||
|
edge: "falling"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
reset(0);
|
||||||
|
addWatch();
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: New App! See the README.MD for details on how to use it.
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
# Smart Switch app for BangleJS
|
||||||
|
|
||||||
|
This app allows you to remotely control devices (or anything else you like!) with:
|
||||||
|
|
||||||
|
* [Bangle.js](https://www.espruino.com/Bangle.js) (Hackable JavaScript Smartwatch)
|
||||||
|
* [EspruinoHub](https://github.com/espruino/EspruinoHub) (Bluetooth Low Energy -> MQTT bridge)
|
||||||
|
* [Node-RED](https://nodered.org) (Flow-based programming tool)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
* Swipe right to turn a device ON
|
||||||
|
* Swipe left to turn a device OFF
|
||||||
|
* BTN1 (top-right) - Previous device (page)
|
||||||
|
* BTN3 (bottom-right) - Next device (page)
|
||||||
|
|
||||||
|
> Currently, devices can only be added/removed/changed by editing them in the app's source code.
|
||||||
|
|
||||||
|
# How to use
|
||||||
|
|
||||||
|
First, you'll need a device that supports BLE.
|
||||||
|
|
||||||
|
Install EspruinoHub following the directions at [https://github.com/espruino/EspruinoHub](https://github.com/espruino/EspruinoHub)
|
||||||
|
Install [Node-RED](https://nodered.org/docs/getting-started)
|
||||||
|
|
||||||
|
## Example Node-RED flow
|
||||||
|
|
||||||
|
Import the following JSON into Node-RED and configure the MQTT IN node to use your EspruinoHub's MQTT instance (default port is 1883):
|
||||||
|
|
||||||
|
```JSON
|
||||||
|
[{"id":"87c6f73e.f22038","type":"mqtt in","z":"a256522.ca0b0b","name":"⌚️BangleJS data","topic":"/ble/advertise/ec:5a:c1:a7:fc:91/data","qos":"2","datatype":"auto","broker":"b961407a.91beb","x":860,"y":100,"wires":[["c37809de.3fc538"]]},{"id":"c37809de.3fc538","type":"function","z":"a256522.ca0b0b","name":"Set topic, remove quotes","func":"msg.topic = \"any_topic_here\";\nmsg.payload = msg.payload.replace(/['\"]+/g, \"\")\n\nreturn msg;","outputs":1,"noerr":0,"x":1070,"y":100,"wires":[["9019be89.5b6d5"]]},{"id":"9019be89.5b6d5","type":"debug","z":"a256522.ca0b0b","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1250,"y":100,"wires":[]},{"id":"b961407a.91beb","type":"mqtt-broker","z":"","name":"","broker":"192.168.1.22","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"hello_there","birthQos":"0","birthPayload":"","closeTopic":"bye_now","closeQos":"0","closePayload":"true","willTopic":"bye_now","willQos":"0","willPayload":"true"}]
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace the topic of the MQTT IN node to use the ID of your Bangle.js device, e.g:
|
||||||
|
|
||||||
|
`/ble/advertise/ec:5a:c1:a7:fc:91/data`
|
||||||
|
|
||||||
|
Once you see the MQTT IN node is configured correctly (it says `connected` below the node itself), try swiping in the Smart Switch app, and
|
||||||
|
you should see some data in the Debug node.
|
||||||
|
|
||||||
|
The possibilities for switching things on and off via Bangle.js are now endless. Have fun!
|
||||||
|
|
||||||
|
# How it works
|
||||||
|
|
||||||
|
This is the code that does the actual [BLE advertising](https://www.espruino.com/BLE%20Advertising) on the watch itself:
|
||||||
|
|
||||||
|
```JS
|
||||||
|
NRF.setAdvertising({
|
||||||
|
0xFFFF: [currentPage, page.state]
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
# Not working?
|
||||||
|
|
||||||
|
If you can't see any data in Node-RED after swiping, check to see if your device is advertising by visiting port 1888 of your EspruinoHub instance:
|
||||||
|
|
||||||
|
You should see something like the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
ec:5a:c1:a7:fc:91 - Bangle.js fc91 (RSSI -83)
|
||||||
|
ffff => {"data":"1,1"}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Any comments?
|
||||||
|
|
||||||
|
[Tweet me!](https://twitter.com/BillyWhizzkid)
|
||||||
|
|
||||||
|
# Future
|
||||||
|
|
||||||
|
PRs welcome!
|
||||||
|
|
||||||
|
[ ] Add an HTML GUI for configuring devices inside the Bangle.js App Loader
|
||||||
|
[ ] Allow enable/disable of buzz/beep on change of device state
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AH4A/AH4A/AH4Ag1gAECyGFAB1bAAmAFooyQFp4uGEoWIwQAEGBgtQFwtcFpAACxAwJFyIvFEAItIMAowFF1IwFF6zqBRhIvIxBetMAYvWdgJeSAAOHFyQvEw5eRBAeIF6+IF5wIHF66+LTJIvlNBaPfRRAved4g0BAASNJd4f+F61cFQYAEFxQ/Bw4vXYAQAFLxms/wABGC2ALyaOBF7BgGLyAweFyIwTF4jyDLxKMBFw4xTGAhhEFpAuKGKQwFeg4ADFxgAZFlgA/AH4A/AH4A/AH4A/AH4AhA"))
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
|
||||||
|
// Learn more!
|
||||||
|
// https://www.espruino.com/Reference#l_NRF_setAdvertising
|
||||||
|
// https://www.espruino.com/Bangle.js#buttons
|
||||||
|
|
||||||
|
// Initial graphics setup
|
||||||
|
g.clear();
|
||||||
|
g.setFontAlign(0, 0); // center font
|
||||||
|
// g.setFont("6x8", 8); // bitmap font, 8x magnified
|
||||||
|
g.setFont("Vector", 40); // vector font, 80px
|
||||||
|
|
||||||
|
// Let the app begin!
|
||||||
|
const storage = require("Storage");
|
||||||
|
|
||||||
|
let currentPage = 0;
|
||||||
|
let pages = [
|
||||||
|
{
|
||||||
|
name: "Downstairs",
|
||||||
|
icon: "light",
|
||||||
|
state: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Upstairs",
|
||||||
|
icon: "switch",
|
||||||
|
state: false
|
||||||
|
}];
|
||||||
|
|
||||||
|
function loadPage(page) {
|
||||||
|
const icon = page.state ? page.icon + "-on" : page.icon + "-off";
|
||||||
|
Bangle.beep();
|
||||||
|
g.clear();
|
||||||
|
g.setFont("Vector", 10);
|
||||||
|
g.drawString("prev", g.getWidth() - 25, 20);
|
||||||
|
g.drawString("next", g.getWidth() - 25, 220);
|
||||||
|
g.setFont("Vector", 15);
|
||||||
|
g.drawString(page.name, g.getWidth() / 2, 200);
|
||||||
|
g.setFont("Vector", 40);
|
||||||
|
g.drawString(page.state ? "On" : "Off", g.getWidth() / 2, g.getHeight() / 2);
|
||||||
|
g.drawImage(storage.read(`${icon}.img`), g.getWidth() / 2 - 24, g.getHeight() / 2 - 24 - 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
function prevPage() {
|
||||||
|
if (currentPage > 0) {
|
||||||
|
currentPage--;
|
||||||
|
loadPage(pages[currentPage]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextPage() {
|
||||||
|
if (currentPage < pages.length - 1) {
|
||||||
|
currentPage++;
|
||||||
|
loadPage(pages[currentPage]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function swipe(dir) {
|
||||||
|
|
||||||
|
const page = pages[currentPage];
|
||||||
|
|
||||||
|
page.state = dir == 1;
|
||||||
|
|
||||||
|
NRF.setAdvertising({
|
||||||
|
0xFFFF: [currentPage, page.state]
|
||||||
|
});
|
||||||
|
|
||||||
|
loadPage(page);
|
||||||
|
|
||||||
|
// optional - this keeps the watch LCD lit up
|
||||||
|
g.flip();
|
||||||
|
|
||||||
|
Bangle.buzz();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bangle.on('swipe', swipe);
|
||||||
|
|
||||||
|
setWatch(prevPage, BTN, {edge: "rising", debounce: 50, repeat: true});
|
||||||
|
setWatch(nextPage, BTN3, {edge: "rising", debounce: 50, repeat: true});
|
||||||
|
|
||||||
|
loadPage(pages[currentPage]);
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AGeJAAwttGMotLGMQiD1uzAAWtGEgtE64ACF5IwbFwYtESUouGFpowaFywvXDIS7CFyIwXLwouSF6peF1ovrRqowWF4heEstlApIveDolfAAIEGF76OGFYQuMF6+zdo4uOF6+tF49lFwK9KF7AAJLxovUGBiOhF+IwLF5guWF+AwKF5YuYGBQvKFzQwJF5IucGBAvIFzwwHF44ugF+AwFF4wui/2CABQvrr1YAAIvjrwoDAAwvjFhFeR8onDX/4vcXxIvkYA73BR0gACYA4umMI4uoGAouqAH4AK"))
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AT5gAGFtoxlFpYxhFp4xeFyYwaFyowZF9wuXGC4vuFzIwVF9wdK53OApIwYDRHN6gAC5oFFF8QoC5wyIMRAvZ5wkERgJbCBQqPfEoKGGL4S/j5i3GFwS/jK5BnIF6owMW4S8KFygvKSIQDFF85bBF8QwKF54uUF+AwJF5wuWF+AwIF5ouYGBAvMFzQwHF5YucGAwvKFzwwFF5IugAAOCAA1erAABF0X+rwoDAAwvjFhFeMYIvkE4QAHF8a/vwS+JF8jAHe4KOkGAaQFroumAAUrAAQtpGAgusAH4A/AFI="))
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AH4A/AH4A/AH4AI1gAEFlgAEz2WAAm6ABwuPxGCAAgJC0wwVGJQtIAAWIGIWXF6gxIEAItIMAgABMCowGFyKSGGCulRhQvHegovVLySRGF6QwBLyjyaF4IuQBAaQX3WmF5wIG0ovXXxaZJYDLuMF8SPHRRCPed4mIcwaNJd7YvBAA4uKH4OXF63+/wuHLxi+YF4JgHLxiOXFwJgHLxmmFwYvXGAqNQFzAwELxKMBdjQwJMAwtCRgovRFpDDIAAjqEFyItLGRQWQAH4A/AH4A/AH4A/AH4A/AH4AP"))
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AH4A/AH4A/AH4Ag1gAECyGFAB1bAAmAFooyQFp4uGEoWIwQAEGBgtQFwtcFpAACxAwJFyIvFEAItIMAowFF1IwFF6zqBRhIvIxBetMAYvWdgJeSAAOHFyQvEw5eRBAeIF6+IF5wIHF66+LTJIvlNBaPfRRAved4g0BAASNJd4f+F61cFQYAEFxQ/Bw4vXYAQAFLxms/wABGC2ALyaOBF7BgGLyAweFyIwTF4jyDLxKMBFw4xTGAhhEFpAuKGKQwFeg4ADFxgAZFlgA/AH4A/AH4A/AH4A/AH4AhA"))
|
||||||
Loading…
Reference in New Issue