Merge branch 'espruino:master' into master

pull/2012/head
awkirk71 2022-06-28 11:10:34 +01:00 committed by GitHub
commit 0f7891e592
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 828 additions and 1192 deletions

View File

@ -1 +1,2 @@
0.01: Basic agenda with events from GB 0.01: Basic agenda with events from GB
0.02: Added settings page to force calendar sync

View File

@ -9,4 +9,4 @@
0.08: Handling of alarms 0.08: Handling of alarms
0.09: Alarm vibration, repeat, and auto-snooze now handled by sched 0.09: Alarm vibration, repeat, and auto-snooze now handled by sched
0.10: Fix SMS bug 0.10: Fix SMS bug
0.11: Use default Bangle formatter for booleans 0.12: Use default Bangle formatter for booleans

View File

@ -6,4 +6,6 @@
0.06: Design and usability improvements. 0.06: Design and usability improvements.
0.07: Improved positioning. 0.07: Improved positioning.
0.08: Select the color of widgets correctly. Additional settings to hide colon. 0.08: Select the color of widgets correctly. Additional settings to hide colon.
0.09: Larger font size if colon is hidden to improve readability further. 0.09: Larger font size if colon is hidden to improve readability further.
0.10: HomeAssistant integration if HomeAssistant is installed.
0.11: Performance improvements.

View File

@ -7,6 +7,7 @@
- Tab left/right of screen to show steps, temperature etc. - Tab left/right of screen to show steps, temperature etc.
- Enable / disable lock icon in the settings. - Enable / disable lock icon in the settings.
- If the "sched" app is installed tab top / bottom of the screen to set the timer. - If the "sched" app is installed tab top / bottom of the screen to set the timer.
- If HomeAssistant is installed, triggers are shown. Simple select the trigger and touch the middle of the screen to send the trigger to HomeAssistant.
- The design is adapted to the theme of your bangle. - The design is adapted to the theme of your bangle.
- The colon (e.g. 7:35 = 735) can be hidden now in the settings. - The colon (e.g. 7:35 = 735) can be hidden now in the settings.

File diff suppressed because one or more lines are too long

View File

@ -1,11 +1,11 @@
{ {
"id": "bwclk", "id": "bwclk",
"name": "BW Clock", "name": "BW Clock",
"version": "0.09", "version": "0.11",
"description": "BW Clock.", "description": "BW Clock.",
"readme": "README.md", "readme": "README.md",
"icon": "app.png", "icon": "app.png",
"screenshots": [{"url":"screenshot.png"}, {"url":"screenshot_2.png"}, {"url":"screenshot_3.png"}], "screenshots": [{"url":"screenshot.png"}, {"url":"screenshot_2.png"}, {"url":"screenshot_3.png"}, {"url":"screenshot_4.png"}],
"type": "clock", "type": "clock",
"tags": "clock", "tags": "clock",
"supports": ["BANGLEJS2"], "supports": ["BANGLEJS2"],

BIN
apps/bwclk/screenshot_4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -591,7 +591,6 @@ function getWeatherIconByCode(code) {
default: default:
return weatherRainy; return weatherRainy;
} }
break;
case 6: case 6:
return weatherSnowy; return weatherSnowy;
case 7: case 7:
@ -607,9 +606,8 @@ function getWeatherIconByCode(code) {
default: default:
return weatherCloudy; return weatherCloudy;
} }
break; default:
default: return undefined;
return undefined;
} }
} }

View File

@ -2,7 +2,7 @@
"id": "football", "id": "football",
"name": "football", "name": "football",
"shortName": "football", "shortName": "football",
"version": "1.00", "version": "1.01",
"type": "app", "type": "app",
"description": "Classic football game of the CASIO chronometer", "description": "Classic football game of the CASIO chronometer",
"icon": "app.png", "icon": "app.png",

View File

@ -1 +1,2 @@
0.01: Release 0.01: Release
0.02: Includeas the ha.lib.js library that can be used by other apps or clocks.

View File

@ -1,13 +1,15 @@
# Home Assistant # Home Assistant
This app integrates your BangleJs into the HomeAssistant. This app integrates your BangleJs into the HomeAssistant.
# How to use # How to use
Click on the left and right side of the screen to select the triggers that you Click on the left and right side of the screen to select the triggers that you
configured. Click in the middle of the screen to send the trigger to HomeAssistant. configured. Click in the middle of the screen to send the trigger to HomeAssistant.
![](screenshot.png) ![](screenshot.png)
# First Setup
# Initial Setup
1.) First of all, make sure that HomeAssistant and the HomeAssistant Android App works. 1.) First of all, make sure that HomeAssistant and the HomeAssistant Android App works.
2.) Open your BangleJs Gadgetbridge App, click on the Settings icon of your BangleJs and enable "Allow Intent Access" 2.) Open your BangleJs Gadgetbridge App, click on the Settings icon of your BangleJs and enable "Allow Intent Access"
@ -22,6 +24,7 @@ configured. Click in the middle of the screen to send the trigger to HomeAssista
This setup must be done only once -- now you are ready to configure your BangleJS to This setup must be done only once -- now you are ready to configure your BangleJS to
control some devices or entities in your HomeAssistant :) control some devices or entities in your HomeAssistant :)
# Setup Trigger # Setup Trigger
1.) Upload the app and all corresponding triggers through the AppStore UI. You must specify 1.) Upload the app and all corresponding triggers through the AppStore UI. You must specify
the display name, the trigger as well as an icon. the display name, the trigger as well as an icon.
@ -38,12 +41,36 @@ The following icons are currently supported:
3.) Don't forget to select the action that should be executed at the bottom of each automation. 3.) Don't forget to select the action that should be executed at the bottom of each automation.
# Default Trigger # Default Trigger
This app also implements two default trigger that can always be used: This app also implements two default trigger that can always be used:
- APP_STARTED -- Will be sent whenever the app is started. So you could do some actions already when the app is sarted without the need of any user interaction. - APP_STARTED -- Will be sent whenever the app is started. So you could do some actions already when the app is sarted without the need of any user interaction.
- TRIGGER -- Will be sent whenever some trigger is executed. So you could generically listen to that. - TRIGGER -- Will be sent whenever some trigger is executed. So you could generically listen to that.
# How to use the library (ha.lib.js) in my own app/clk
This app inlcludes a library that can be used by other apps or clocks
to read all configured intents or to send a trigger. Example code:
```js
// First of all impport the library
var ha = require("ha.lib.js");
// You can read all triggers that a user configured simply via
var triggers = ha.getTriggers();
// Get display name and icon of trigger
var display = triggers[0].display;
var icon = triggers[0].getIcon();
// Trigger the first configured trigger
ha.sendTrigger(triggers[0].trigger);
// Send a custom trigger that is not configured by a user
ha.sendTrigger("MY_CUSTOM_TRIGGER");
```
# FAQ # FAQ
## Sometimes the trigger is not executed ## Sometimes the trigger is not executed

View File

@ -1,72 +1,10 @@
var storage = require("Storage"); /**
* This app uses the ha library to send trigger to HomeAssistant.
*/
var ha = require("ha.lib.js");
var W = g.getWidth(), H = g.getHeight(); var W = g.getWidth(), H = g.getHeight();
var position=0; var position=0;
var triggers = ha.getTriggers();
// Note: All icons should have 48x48 pixels
function getIcon(icon){
if(icon == "light"){
return {
width : 48, height : 48, bpp : 1,
transparent : 0,
buffer : require("heatshrink").decompress(atob("AAMBwAFE4AFDgYFJjgFBnAFBjwXBvAFBh4jBuAFCAQPwAQMHAQPgEQQCBEgcf/AvDn/8Aof//5GDAoJOBh+BAoOB+EP8YFB4fwgfnAoPnGANHAoPjHYQFBHYQFd44pDg47C4/gh/DIIZNFLIplGgF//wFIgZ9BRIUHRII7Ch4FBUIUOAoKzCjwFEhgCBmDpIVooFFh4oCAA4LFC5b7BAob1BAYI="))
};
} else if(icon == "door"){
return {
width : 48, height : 48, bpp : 1,
transparent : 0,
buffer : require("heatshrink").decompress(atob("AAM4Aok/4AED///Aov4Aon8DgQGBAv4FpnIFKJv4FweAQFFAgQFB8AFDnADC"))
};
} else if (icon == "fire"){
return {
width : 48, height : 48, bpp : 1,
transparent : 0,
buffer : require("heatshrink").decompress(atob("ABsDAokBwAFE4AFE8AFE+AFE/AFJgf8Aon+AocHAokP/8QAokYAoUfAok//88ApF//4kDAo//AgMQAgIFCjgFEjwFCOYIFFHQIFDn/+AoJ/BAoIqBAoN//xCBAoI5BDIPAgP//gFB8AFChYFBgf//EJAogOBAoSgBAoMHAQIFEFgXAAoJEBv4FCNoQFGVYd/wAFEYYIFIvwCBDoV8UwQCBcgUPwDwDfQMBaIYADA"))
};
}
// Default is always the HA icon
return {
width : 48, height : 48, bpp : 1,
transparent : 0,
buffer : require("heatshrink").decompress(atob("AD8BwAFDg/gAocP+AFDj4FEn/8Aod//wFD/1+FAf4j+8AoMD+EPDAUH+OPAoUP+fPAoUfBYk/C4l/EYIwC//8n//FwIFEgYFD4EH+E8nkP8BdBAonjjk44/wj/nzk58/4gAFDF4PgCIMHAoPwhkwh4FB/EEkEfIIWAHwIFC4A+BAoXgg4FDL4IFDL4IFDLIYFkAEQA=="))
};
}
// Try to read custom actions, otherwise use default
var triggers = [
{display: "Not found.", trigger: "NOP", icon: "ha"},
];
try{
triggers = storage.read("ha.trigger.json");
triggers = JSON.parse(triggers);
} catch(e) {
// In case there are no user triggers yet, we show the default...
}
function sendIntent(trigger){
var retries=3;
while(retries > 0){
try{
// Send a startup trigger such that we could also execute
// an action when the app is started :)
Bluetooth.println(JSON.stringify({
t:"intent",
action:"com.espruino.gadgetbridge.banglejs.HA",
extra:{
trigger: trigger
}})
);
retries = -1;
} catch(e){
retries--;
}
}
}
function draw() { function draw() {
@ -78,7 +16,7 @@ function draw() {
var w = g.stringWidth(trigger.display); var w = g.stringWidth(trigger.display);
g.setFontAlign(-1,-1); g.setFontAlign(-1,-1);
var icon = getIcon(trigger.icon); var icon = trigger.getIcon();
g.setColor(g.theme.fg).drawImage(icon, 12, H/5-2); g.setColor(g.theme.fg).drawImage(icon, 12, H/5-2);
g.drawString("Home", icon.width + 20, H/5); g.drawString("Home", icon.width + 20, H/5);
g.drawString("Assistant", icon.width + 18, H/5+24); g.drawString("Assistant", icon.width + 18, H/5+24);
@ -112,13 +50,11 @@ Bangle.on('touch', function(btn, e){
} }
if(!isRight && !isLeft){ if(!isRight && !isLeft){
ha.sendTrigger("TRIGGER");
// Send a default intent that we triggered something.
sendIntent("TRIGGER");
// Now send the selected trigger // Now send the selected trigger
Bangle.buzz(80, 0.6).then(()=>{ Bangle.buzz(80, 0.6).then(()=>{
sendIntent(triggers[position].trigger); ha.sendTrigger(triggers[position].trigger);
setTimeout(()=>{ setTimeout(()=>{
Bangle.buzz(80, 0.6); Bangle.buzz(80, 0.6);
}, 250); }, 250);
@ -126,12 +62,14 @@ Bangle.on('touch', function(btn, e){
} }
}); });
// Send intent that the we started the app. // Send intent that the we started the app.
sendIntent("APP_STARTED"); ha.sendTrigger("APP_STARTED");
// Next load the widgets and draw the app // Next load the widgets and draw the app
Bangle.loadWidgets(); Bangle.loadWidgets();
Bangle.drawWidgets(); Bangle.drawWidgets();
// Draw app
draw(); draw();
setWatch(_=>load(), BTN1); setWatch(_=>load(), BTN1);

80
apps/ha/ha.lib.js Normal file
View File

@ -0,0 +1,80 @@
/**
* This library can be used to read all triggers that a user
* configured and send a trigger to homeassistant.
*/
function _getIcon(trigger){
icon = trigger.icon;
if(icon == "light"){
return {
width : 48, height : 48, bpp : 1,
transparent : 0,
buffer : require("heatshrink").decompress(atob("AAMBwAFE4AFDgYFJjgFBnAFBjwXBvAFBh4jBuAFCAQPwAQMHAQPgEQQCBEgcf/AvDn/8Aof//5GDAoJOBh+BAoOB+EP8YFB4fwgfnAoPnGANHAoPjHYQFBHYQFd44pDg47C4/gh/DIIZNFLIplGgF//wFIgZ9BRIUHRII7Ch4FBUIUOAoKzCjwFEhgCBmDpIVooFFh4oCAA4LFC5b7BAob1BAYI="))
};
} else if(icon == "door"){
return {
width : 48, height : 48, bpp : 1,
transparent : 0,
buffer : require("heatshrink").decompress(atob("AAM4Aok/4AED///Aov4Aon8DgQGBAv4FpnIFKJv4FweAQFFAgQFB8AFDnADC"))
};
} else if (icon == "fire"){
return {
width : 48, height : 48, bpp : 1,
transparent : 0,
buffer : require("heatshrink").decompress(atob("ABsDAokBwAFE4AFE8AFE+AFE/AFJgf8Aon+AocHAokP/8QAokYAoUfAok//88ApF//4kDAo//AgMQAgIFCjgFEjwFCOYIFFHQIFDn/+AoJ/BAoIqBAoN//xCBAoI5BDIPAgP//gFB8AFChYFBgf//EJAogOBAoSgBAoMHAQIFEFgXAAoJEBv4FCNoQFGVYd/wAFEYYIFIvwCBDoV8UwQCBcgUPwDwDfQMBaIYADA"))
};
}
// Default is always the HA icon
return {
width : 48, height : 48, bpp : 1,
transparent : 0,
buffer : require("heatshrink").decompress(atob("AD8BwAFDg/gAocP+AFDj4FEn/8Aod//wFD/1+FAf4j+8AoMD+EPDAUH+OPAoUP+fPAoUfBYk/C4l/EYIwC//8n//FwIFEgYFD4EH+E8nkP8BdBAonjjk44/wj/nzk58/4gAFDF4PgCIMHAoPwhkwh4FB/EEkEfIIWAHwIFC4A+BAoXgg4FDL4IFDL4IFDLIYFkAEQA=="))
};
}
exports.getTriggers = function(){
var triggers = [
{display: "Empty", trigger: "NOP", icon: "ha"},
];
try{
triggers = require("Storage").read("ha.trigger.json");
triggers = JSON.parse(triggers);
// We lazy load all icons, otherwise, we have to keep
// all the icons n times in memory which can be
// problematic for embedded devices. Therefore,
// we lazy load icons only if needed using the getIcon
// method of each trigger...
triggers.forEach(trigger => {
trigger.getIcon = function(){
return _getIcon(trigger);
}
})
} catch(e) {
// In case there are no user triggers yet, we show the default...
}
return triggers;
}
exports.sendTrigger = function(triggerName){
var retries=3;
while(retries > 0){
try{
// Now lets send the trigger that we sould send.
Bluetooth.println(JSON.stringify({
t:"intent",
action:"com.espruino.gadgetbridge.banglejs.HA",
extra:{
trigger: triggerName
}})
);
retries = -1;
} catch(e){
retries--;
}
}
}

View File

@ -1,7 +1,7 @@
{ {
"id": "ha", "id": "ha",
"name": "HomeAssistant", "name": "HomeAssistant",
"version": "0.01", "version": "0.02",
"description": "Integrates your BangleJS into HomeAssistant.", "description": "Integrates your BangleJS into HomeAssistant.",
"icon": "ha.png", "icon": "ha.png",
"type": "app", "type": "app",
@ -19,6 +19,7 @@
], ],
"storage": [ "storage": [
{"name":"ha.app.js","url":"ha.app.js"}, {"name":"ha.app.js","url":"ha.app.js"},
{"name":"ha.lib.js","url":"ha.lib.js"},
{"name":"ha.img","url":"ha.icon.js","evaluate":true} {"name":"ha.img","url":"ha.icon.js","evaluate":true}
] ]
} }

View File

@ -1 +1,3 @@
0.01: Release 0.01: Release
0.02: Recfactoring and show weather data
0.03: Show sizes for used, free and trash through storage.getStats

View File

@ -1,27 +1,99 @@
var s = require("Storage"); const storage = require("Storage");
const locale = require('locale'); const locale = require('locale');
var ENV = process.env; var ENV = process.env;
var W = g.getWidth(), H = g.getHeight(); var W = g.getWidth(), H = g.getHeight();
var screen = 0; var screen = 0;
const maxScreen = 2;
var screens = [
{
name: "General",
items: [
{name: "Steps", fun: () => getSteps()},
{name: "HRM", fun: () => getBpm()},
{name: "", fun: () => ""},
{name: "Temp.", fun: () => getWeatherTemp()},
{name: "Humidity", fun: () => getWeatherHumidity()},
{name: "Wind", fun: () => getWeatherWind()},
]
},
{
name: "Hardware",
items: [
{name: "Battery", fun: () => E.getBattery() + "%"},
{name: "Charge?", fun: () => Bangle.isCharging() ? "Yes" : "No"},
{name: "TempInt.", fun: () => locale.temp(parseInt(E.getTemperature()))},
{name: "Bluetooth", fun: () => NRF.getSecurityStatus().connected ? "Conn" : "NoConn"},
{name: "GPS", fun: () => Bangle.isGPSOn() ? "On" : "Off"},
{name: "Compass", fun: () => Bangle.isCompassOn() ? "On" : "Off"},
]
},
{
name: "Software",
items: [
{name: "Firmw.", fun: () => ENV.VERSION},
{name: "Git", fun: () => ENV.GIT_COMMIT},
{name: "Boot.", fun: () => getVersion("boot.info")},
{name: "Settings.", fun: () => getVersion("setting.info")},
]
},
{
name: "Storage [kB]",
items: [
{name: "Total", fun: () => storage.getStats().totalBytes>>10},
{name: "Free", fun: () => storage.getStats().freeBytes>>10},
{name: "Trash", fun: () => storage.getStats().trashBytes>>10},
{name: "", fun: () => ""},
{name: "#File", fun: () => storage.getStats().fileCount},
{name: "#Trash", fun: () => storage.getStats().trashCount},
]
},
];
function getWeatherTemp(){
try {
var weather = storage.readJSON('weather.json').weather;
return locale.temp(weather.temp-273.15);
} catch(ex) { }
return "?";
}
function getWeatherHumidity(){
try {
var weather = storage.readJSON('weather.json').weather;
return weather.hum = weather.hum + "%";
} catch(ex) { }
return "?";
}
function getWeatherWind(){
try {
var weather = storage.readJSON('weather.json').weather;
var speed = locale.speed(weather.wind).replace("mph", "");
return Math.round(speed * 1.609344) + "kph";
} catch(ex) { }
return "?";
}
function getVersion(file) { function getVersion(file) {
var j = s.readJSON(file,1); var j = storage.readJSON(file,1);
var v = ("object"==typeof j)?j.version:false; var v = ("object"==typeof j)?j.version:false;
return v?((v?"v"+v:"Unknown")):"NO "; return v?((v?"v"+v:"Unknown")):"NO ";
} }
function drawData(name, value, y){
g.drawString(name, 5, y);
g.drawString(value, 100, y);
}
function getSteps(){ function getSteps(){
try{ try{
return Bangle.getHealthStatus("day").steps; return Bangle.getHealthStatus("day").steps;
} catch(e) { } catch(e) {
return ">= 2v12"; return ">2v12";
} }
} }
@ -29,53 +101,36 @@ function getBpm(){
try{ try{
return Math.round(Bangle.getHealthStatus("day").bpm) + "bpm"; return Math.round(Bangle.getHealthStatus("day").bpm) + "bpm";
} catch(e) { } catch(e) {
return ">= 2v12"; return ">2v12";
} }
} }
function drawData(name, value, y){
g.drawString(name, 10, y);
g.drawString(value, 100, y);
}
function drawInfo() { function drawInfo() {
g.reset().clearRect(Bangle.appRect); g.reset().clearRect(Bangle.appRect);
var h=18, y = h;//-h; var h=18, y = h;//-h;
// Header // Header
g.setFont("Vector", h+2).setFontAlign(0,-1); g.drawLine(0,25,W,25);
g.drawString("--==|| INFO ||==--", W/2, 0); g.drawLine(0,26,W,26);
// Info body depending on screen
g.setFont("Vector",h).setFontAlign(-1,-1); g.setFont("Vector",h).setFontAlign(-1,-1);
screens[screen].items.forEach(function (item, index){
drawData(item.name, item.fun(), y+=h);
});
// Dynamic data // Bottom
if(screen == 0){ g.drawLine(0,H-h-3,W,H-h-3);
drawData("Steps", getSteps(), y+=h); g.drawLine(0,H-h-2,W,H-h-2);
drawData("HRM", getBpm(), y+=h); g.setFont("Vector",h-2).setFontAlign(-1,-1);
drawData("Battery", E.getBattery() + "%", y+=h); g.drawString(screens[screen].name, 2, H-h+2);
drawData("Voltage", E.getAnalogVRef().toFixed(2) + "V", y+=h);
drawData("IntTemp.", locale.temp(parseInt(E.getTemperature())), y+=h);
}
if(screen == 1){
drawData("Charging?", Bangle.isCharging() ? "Yes" : "No", y+=h);
drawData("Bluetooth", NRF.getSecurityStatus().connected ? "Conn." : "Disconn.", y+=h);
drawData("GPS", Bangle.isGPSOn() ? "On" : "Off", y+=h);
drawData("Compass", Bangle.isCompassOn() ? "On" : "Off", y+=h);
drawData("HRM", Bangle.isHRMOn() ? "On" : "Off", y+=h);
}
// Static data
if(screen == 2){
drawData("Firmw.", ENV.VERSION, y+=h);
drawData("Boot.", getVersion("boot.info"), y+=h);
drawData("Settings", getVersion("setting.info"), y+=h);
drawData("Storage", "", y+=h);
drawData(" Total", ENV.STORAGE>>10, y+=h);
drawData(" Free", require("Storage").getFree()>>10, y+=h);
}
if(Bangle.isLocked()){
g.setFont("Vector",h-2).setFontAlign(-1,-1);
g.drawString("Locked", 0, H-h+2);
}
g.setFont("Vector",h-2).setFontAlign(1,-1); g.setFont("Vector",h-2).setFontAlign(1,-1);
g.drawString((screen+1) + "/3", W, H-h+2); g.drawString((screen+1) + "/" + screens.length, W, H-h+2);
} }
drawInfo(); drawInfo();
@ -88,14 +143,15 @@ Bangle.on('touch', function(btn, e){
var isRight = e.x > right; var isRight = e.x > right;
if(isRight){ if(isRight){
screen = (screen + 1) % (maxScreen+1); screen = (screen + 1) % screens.length;
} }
if(isLeft){ if(isLeft){
screen -= 1; screen -= 1;
screen = screen < 0 ? maxScreen : screen; screen = screen < 0 ? screens.length-1 : screen;
} }
Bangle.buzz(40, 0.6);
drawInfo(); drawInfo();
}); });
@ -104,5 +160,4 @@ Bangle.on('lock', function(isLocked) {
}); });
Bangle.loadWidgets(); Bangle.loadWidgets();
for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";} Bangle.drawWidgets();
// Bangle.drawWidgets();

View File

@ -1,7 +1,7 @@
{ {
"id": "info", "id": "info",
"name": "Info", "name": "Info",
"version": "0.01", "version": "0.03",
"description": "An application that displays information such as battery level, steps etc.", "description": "An application that displays information such as battery level, steps etc.",
"icon": "info.png", "icon": "info.png",
"type": "app", "type": "app",
@ -11,7 +11,8 @@
"screenshots": [ "screenshots": [
{"url":"screenshot_1.png"}, {"url":"screenshot_1.png"},
{"url":"screenshot_2.png"}, {"url":"screenshot_2.png"},
{"url":"screenshot_3.png"}], {"url":"screenshot_3.png"},
{"url":"screenshot_4.png"}],
"storage": [ "storage": [
{"name":"info.app.js","url":"info.app.js"}, {"name":"info.app.js","url":"info.app.js"},
{"name":"info.img","url":"info.icon.js","evaluate":true} {"name":"info.img","url":"info.icon.js","evaluate":true}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
apps/info/screenshot_4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -1 +1,2 @@
0.01: New App! 0.01: New App!
0.11: Changes...

View File

@ -1 +1,3 @@
0.01: First release 0.01: First release
0.02: Improve battery life, sprite resolution, fix launcher issue and unaligned text bug
0.03: Reduce code size, refresh once a minute and faster refresh

View File

@ -7,641 +7,107 @@ const w = g.getWidth();
/// ///////////////////////////////////////// /// /////////////////////////////////////////
const katakana = {}; const katakana = {};
const hiragana = {}; const hiragana = {};
katakana.A = { function image(x,y,b) {
width: 32, return {
height: 32, bpp:1, width:x,height:y,
bpp: 1, buffer:require('heatshrink').decompress(atob(b))
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAjAEBfv4B/+yeAXwAOgBAAPAAAEHAAABzAAAAPgAAADgAAAAwAAAAMAAAAGAAAABgAAAAYAAAAMAAAADAAAABgAAAAYAAAAMAAAAGAAAADAAAABgAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=') };
}; }
hiragana.A = { katakana['A'] = image(56, 51, "v//AAfwAon//AGF/wGT/gGM/A3F/BDEn/wJQoGCj4RB//gAxUB//AAwcDAwsH/+AAwcP/4tCAwMf/wGEn/8Awl/JYYGBKQkf/I9DAwJgBGwQGDGwRlBAwJsE+42DAwPzGwYGB+J7EQIIvDQIIFEAw5DEAwRDDgCIEAxCPBKIcAR4IhER4hnCLAg9BLAgoBAwgoBcQiCBMwj0BHogGBHogGBfoooEQQREFEIgGBAokAhAGFA=");
width: 32, katakana['I'] = image(54, 55, "AAkEAws+AokB/wGEg//Awk//gTE//gAwcPCYt/CYkDCYsfCYv//A0F4A0ECYg0BCYggBCYn/KwhBBGgl/EAgtBEAgMBEAZOBEAgMBEAYZB/+ABggTDBgQnDAoIaDJoIaDFgIABDQQFC74aBBgX8v4aBEwWBDQQgB/EHDQQ6BwEfGoX/+AJBDQMDWAKMBDQMPAQIaDiBFCPAgaDU4hrDDQiuDDX4acSAIaCA=");
height: 32, katakana['U'] = image(52, 55, "AAMP/gGE//ABlH/AAnvAon+Bk5EDv/vIgcHBkHPBgZwBBgn/Bi8B/+PBgcf/AMFw/wBgYEDgED/6qEv4MEKYK3F8AFDj7EED4LREv/4CQn/wASEFginBDAgfEDAIfDn67BC4YABH4QXBCQcHZoQkEEoYMCHAYlBFYZEBLwk/MgpQEAAw");
bpp: 1, katakana['E'] = image(58, 45, "h//AAfwgYGE/0AAwn/wE/AwngDgv4DjhDCv/wJQkf/gGEg//AwkB//AA4gc/Dn4cjbAv/34GF94GF/YGF/wcjwA=");
transparent: 0, katakana['O'] = image(57, 54, "AAcf+AGEh/8AwkH/wGEgf/AwkB/+AA4n/4AGEv/gAwk/GIsf/A4P/4AE+F/Awn4n4GE/kfAwn+h4cFg4GFwYGF4IGFKwYFBMQpxFAwJxEAwJxEAwJxEAwJxEK4JxEAwKqEMoQGE/o4En/8HAl//iqEAwKqEv/+VQgNBVQgNBcYgNBcYhLBcYhSCHAQKBAwI4CAwY4CD4IGBHASxBAYI4CAwY4CYwIGBHAQGBD4I4CBIJfCHASmDHAV/PYQ4Cj5QCHAUPLwQ4CgQGCOIgABOIgABHAIGEAAY=");
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAACAAAAAwAAAAIAAAACAAAABgAAAAZ4AAGf4AAA/gAAAAQAAAAEAAAABBAAAAQwAAAN/wAADiGAADxAwABswEAAhYBgAQUAYAMHAEACBgDABh4AwAZ2AYAD4gcAAQAcAAAAAAAAAAAAAAAAAAAAAAA=') katakana['KA'] = image(54, 54, "AAMP/AGEv/gAocB/+AAwcH/wTEj4arg//AAf+j4GE/F/AwnhAon/w4aZHAMP/hTEn/wKYn/4BTDgf/KYgQCDQYQCBIQQDBIQQCBIc/DQouCDQQuCEghJBEhITBH4RTBLoRTEBIJTGCAUPNwoTCDQQWBDoIuCj4TCJIX/CYQ/BZQInBH4U//0HwBTBGgPwXAXwh4PBXAXAv4PCZIIgBEYTJBn5SBDQXABAIzBCYJcCDQXwgbOCAwIDBQgI4CgEOJwIADkAGFA");
}; katakana['KI'] = image(58, 55, "AAU+Awv/4AGEn/wAwkP/gGEgf/Dkk/CAc//4ABwAGBj4GC8ATBAAf4h4GE/woBAAmAAwvgFAYcIwAcD/BFDFARFD/kBIoYACv5FBAAcfRL94DgkfHgf/95EBD4RgDD4MHLwf8AogAd+CPFGwiJCS4XHJgSGB8CJEkCJJUwYABg5pDD4amTNwKmXYbgcDLoY=");
katakana.I = { katakana['KU'] = image(55, 55, "AAMHwAGEh/8Awkf/AGEv/wAwn/4AFDgf/EQkH/whF/4ACAwM/AoQQCBgY5BgIGDHIMHAwY5Bh4GD8AhEIAQFDIAIhBBIJACEIJpEj45CNIV/NgRpBDQIrBEoPgDQJlBEoQaDEoV/RwUP/wPBQ4Uf/gPBQ4QsBKAKSD8BvCSQXDDQYYBNYIaCGYIqBDQU//kPXoYYBj5QCEIPgj60DKoMcWga7FKoYABKogaDbojPBbojMDGob/ECYJBCbgYaDE4IaEPoIaDEAI1EbYQZECYgtBCZQGCLol/KwxxEAwJqEgIMFgIZEgA=");
width: 32, katakana['KE'] = image(60, 54, "AAMcAwsD/4HFn/wBxl/8AGEg/+BxkP/gOF//ABxcB/+AA4kf/BCGAAZOBv4HEIQIOGAwgOBh4OFGYIOFn4OFEgoOBAwvgh52BKgYDBOwJUDv5nBBwY6BAYM/BwIKBJgJjBBQSbCWoQVBRgK1D/4oDBwJJBWos/WIS1CgIVCJoRGBWowCCj61HYgpRCdIjEGLgTLEIwTLEfAv/GYqtBEghyBGYjoCAwwkDAwQVEYwYjEHQt/CopeBQgQOEIIgOBPgxeFgZ7FA");
height: 32, katakana['KO'] = image(49, 46, "v//AAYFF34FE74FE94FE+4FE/IFE/gFE/w0Dgf/AocB/+AAwf/4BHE8AFDn/wAocf/AFDh/8AocHGH4w6YZf7Aon9YYoFEejBhEAAIA=");
bpp: 1, katakana['SA'] = image(58, 53, "AAcD/wDBg4DC//AgEB/+AgE/+AKBv/ggEP/gGBj/4DgP/DnU//4A34CQ+DAIcEDAIcDDAQDDDAYDCDAYDD/4cDIgJADAAUfIAQACh4jCAAUHD4QACJwIfBAAQtBEYgGBI4QUDFQkP/4qEVYQvEAAIxCEIK5CBwV/AwsfAwocCAwYcCJogcBNIp3F");
buffer: atob('AAAAAAAAAAAAAAAAAAAAwAAAAGAAAADwAAAA0AAAAYAAAAUgAAAGAAAAFAAAADgAAAA8AAAA2AAAAZgAAAYYAAAMGAAAMFgAAGAYAAGAGAACABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAAAAAAAAAAAAAAAAAAAA=') katakana['SI'] = image(56, 52, "gFwAwt+Awv/8AGF/gFDgP//4GGCocDAwIVDBoX/wAHCn4VFg4GB4AxEAwsfAworBEQYABv4GFj4DCjgrCBQYRFn/4JQfAIgIGD+F/JQcD/gGBMARQCOwcH/wNBCoUP/0PAwIrBj/8OwQGBn4fBGIIGCAQIlB+BcBAQKvDBIQRB8AfBIQUH4AXBP4RXBGgJmERoJsFAwv//yaFbYghBQIYaCeAi9FPQTZGdxKFCFASECFAZPBEIgNCJQaZEAwhDDAwRJDTAYGEQAiQBPIgAGA");
}; katakana['SU'] = image(60, 51, "gH/AAYGBh4GD/AOG4AOF/gONDo+ABxAACgY7CAAd/+AGEg4OG//gAwkP/wGEgJCCAAcfKIQzEIQIzEIQozOj4zFEgIzFn4kHGYv/M4okIGYt/IQqXBFghuBHYs/bAY6DCwrJECod/HgYVB8ZLEcoMfLQYECCwYVB+BTBCwT7CCwYrBAYIKCCoQDC8BXBEIQSBNoQVBBYP4EAIoCOQPHCoYTB/xdBIwQ8B+6SET4N/dYn/4aCFFgKRFgC+EgPghivEAoI");
hiragana.I = { katakana['SE'] = image(57, 53, "gEH/wGEgf/AwkB/+AA4n/4AGEv/gAwk/+AGEj/4AwkP/g4JjA4EBQQ4D/4DD4E/AwIuBv/vAoP/FwILCAAIuBv4GEBgn//wFEAwITEh//CgfwAwMfCIRGB/4BB/5xBAgJTBIQQGBwP/75CBAwOAD4JCBAwRmDDIKYBOIQGDOIQGDOIQbBAwSqBAwiqBAwiqBDYg4Cv4GCHAUfAwQ4Cg4GCHAUBbwbjnHAgADcYYADUYQxEEYq6CVwbDBdQi6CZQYqBAAZcCAwY1BEYi5DAAQ8CegfgA=");
width: 32, katakana['SO'] = image(52, 52, "gGAAol8AYUD/Ef4AGCn/3/wFCg/+v/wAwV/8//Bgk//AMD8f/FoQMBj/8Bgfg//gBgcPFoYMBFocP/kHFof/4AtDBgMDFoYMBFoYMBgIIBgADBwAtDj4dBHQQMCFoYqCHQQqCFoc/BIIPCCwQtDKYIpBB4IwDIAQwCh45CBIVAFgSmDFIaaDOIYfCVgYfBRYYfCTASTCUoY1BQgZPCD4l/D4kfH4g4BH4YYBH4gFBGQd//4yDBYIyDn4SEJQIlEBgRXEHAg+BFYZRGZYQADBYgAG");
height: 32, katakana['TA'] = image(55, 56, "AAMHwAGEh/8Awkf/AGEv/gAwn/4AFDgf/EQkH/4oF/4ACAwM/AoX+FAQGCHIMBCYY5BEIIAC+AhFIAIhDHIQFDF4IhBJQMHF4JDDNIUfHIRpCv5sCn/wDQJsCDwIaBEIIKBwEf/9gOAQaB/gbBFAIPB+YsC/AaB54RBFAIaBAIOAEoJvBOgPh/+DNAJWB+//DQPBQIZyBM4f4LQSQC8EPKAIpBFAMPPgKKCgEcYIZwBiAGDbohwEZ4bdEFILxFf4ghBXwLjEDQhLBCYoaEE4IaDdIQaDBgLBCDIRQENYYTIewRkEAwJCFHYicBOIkAEAhDBS4IAJ");
bpp: 1, katakana['TI'] = image(57, 54, "AAkGAwsfwAGE//gAocP//wBgn//gEBgIFBAAIeBAof/wAYBAwkHAof+gEDAwf4E4YAB4AGBv4TDAAM/AwoxDKQhABLQwiCAAV/MIglBMIglBHwRwDNARbF//3Awv7Awv9Awv+Awv/MQQAD34GF74GFKAUHOIYABSAJxGaYp4Uv54FP40/P4oGHQwQGKKgt/AwrUEMIQGEVYIGLg4bMFII+Fv5TGNAsPQgsHTIoAG");
transparent: 0, katakana['TU'] = image(54, 53, "AAMBwAGEj4FEgf8AYPwgFgn/4BIP/g+Av/ggEP/n/gP/4EAv/v/wQBFQP/z/4CAMAg/+DAMfEIICBDAN/FgN/8YYBBAIaBw4hDDQIVBAYMAn/wDAIhCCwIhDCwIBBwAIBHAIYBEIQYDBAIuBwAjBFQghCJgQhEAIIhDEYQPBh5HBM4IhDQQQhCwYeBCwMBCoSPB/0CIQQhBAQKWDvytBCYTBDv5tBZYYTCAAQTCAAYTFHAITEj4TF/4TEh4TFv4TEg//JgIMDMYIMEO4ImD/53BAAM/AwIsEEAgFBEAZNBIIgTCFocfJwo6BPgpHEgZAEgEOAogAGA==");
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAwAAgAEAAEABAAAgAQAAMAGAABAAgAAYAIAAGACAAAwAQAAMAEAADABiAAQAIgAAADQAAAAcAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=') katakana['TE'] = image(57, 51, "h//AAfwg4GE/kDAwn+gIGE/8AAwuAv4GE4E/Awngj4GFNWJNF/gGF/5UF/+/AwvfAwvvAwv3Awv7GJn8IQV/4BJEv59Fn/wAwkf/DJFEAYABg/+AwjJBAxbQBwAGFH4gGBH4gGIIwgGNG4IGEg//LYjyBAwiyBAxc/EQoGGFIJTLdYJvEgF+fIsYAwo=");
}; katakana['TO'] = image(42, 54, "//AAgU/+AECh/8AgUD/4U/CgYPDn//wAUC/4VCCgIlDAgIKCCgIKCCgP//wUD//gCgQKCn/zBQQ+BDYP8CgMBEAQBBj4KBKYIKC54yBBQP7KYIKCG4QKB35YBBQIUCGQPjNAUD+BXDnB9Dgy8/CicAA=");
katakana.U = { katakana['MA'] = image(57, 50, "/4AE/l/A4s/AwvfAwoAN/YGF/oxGHokf/wGLh4GN/4GSg4GChgGDwARBAw3gAwv4Awo7BAwn/4ACBAwIKB+AGDgJtBAwcAUgOPAwYLB94GDgaFCAwTBDAwcfAwoyBAwgyBAwgyCAwgcBAwgyBNgL0ENgIADn6oHDijhFW4wcB4AGDKwPwBwl/fwzUJDgZOFgAGGngGFhADCA");
width: 32, katakana['MI'] = image(52, 53, "gPwAwkf/wFDgf///gAwU/AwIVCBgX//AME//8gEHAoQGCBgYGCv4GDFIMPBggoE4A2CCoIuCAweAAwc/BghYBMwswNw0PNwkBGAIbEG4gMCOoYMCOoQMDAwRnE4BYDKYQTEKYRuCKYY8GgCjDAAV+LAtgcTMDbYhTCHobICBwbBDBghZDZwmAZoYGCAogGBCYgiBEIidCBwQ2DS4QMCVYT2CSAb2DBoLpFn72EdJAA==");
height: 32, katakana['MU'] = image(59, 54, "AAMDwAHFv/AAwkf/gVF/4VG8AGEh4VHFgoVPFdZBdRogVBgP4CokBFogVBn/wTIkHEwYrCv4ODCoMP/wVDFIP/JYQVCBwgVBGYLICCoTIDCoQCBBwQhCn5RCCoR/DNoZCDDIRRDCoQODg4+CIQYvGCoZCCCoZRDAQV//4SBRAM//4ABwEfAgQAB/ARBAAkPAwvxAwv+Dgv/8YGF/gkD/xCB543DH4P5AoaBBewsAvgGFhgGFAAQ=");
bpp: 1, katakana['ME'] = image(55, 54, "AAcB8AGEgf/AwkP/wGEj/8Awk/+AGEv4iF//AFAuAAwcHFAsPFA34AYNwFAQvBgICCFAUHCAIoDDwQoDn4DBKIf/MYIoCDwIGB/5RBAwWDKIYGB456Dv//75RDAwP/JQQmBAwJ6Dj4GBOYYGCOYcP/5zEg//OYgGNDYw3BAwgvBAwaABAwgaBOARZC/wGDOoP8MQI1D+AGDFwPAAwJaBDAQNCJIc/AQJsBTYL3COQc/4ATBXoYdCSgU8J4SNCmCNCNQqoDAwQuBAwgFDFAITEAwK1DAAKZEAAIMFAA4=");
buffer: atob('AAAAAAAAAAAAAQAAAAHAAAAAwAAAAICAAACIAAAAgIABQa3AAP7q4ADQANAAwADAAMABgADAAYAAwAGAAMADAADAAwAAwAYAAMAGAABADAAAABgAAAAwAAAAMAAAAGAAAACQAAADAAAABgAAAAwAAAAoAAAAAAAAAAAAAAAgAAA=') katakana['MO'] = image(55, 49, "j//AAfAv4GFAon/wIGFgYFE/0HAwn8h4GE/AvF8A4Bv4DCAAQzBAocB/+AAwYxBCYkH/wGEh/8MIv4Awk/+AGEGyJfFAFP9AwpOBNuikeAwxfEHoLpFNoZACAwZABIgIACJYYABIAYGCIAYwCHIoABA=");
}; katakana['NA'] = image(57, 55, "AAV/8AGEn/wAwkf/AGEh/8AwkH/wGEgf/AwkB/+AA4n/4A4rGoIAE/IGF/wGF/9/Awu/AwvfAwvvAwv3AwpQCOOqqEWLV/H4pGGn5GFAw0fJosfJooGGn4GGKgq6BLQoGEg4GFh4GFPoIpEDYIwFv5MFLQ4GFg6EFgaZFAAw");
hiragana.U = { katakana['NI'] = image(56, 43, "h//AAf4A25+/AH4AuWggA5A=");
width: 32, katakana['NU'] = image(55, 51, "g//AAcAh4GFj4FD/0An4GD/kAv4GD/EADQnwgIGE8EDAwnAAwuAIIgvBAAcPF4IADn4vBAAd/8AGEFAIDBAQIsBFAMDCAIoDh4eBj4oCj4GBFAd/CIJRBgBZCAQIlD/+HQIIGD54oCNwZKDPQZPDOYRdDOYqmBOYi0BOYjCBBogGGYQSAEAwimDGATdDAwQTBH4JFBLIP8AwYTB+AqBAwITB4AGBE4bADBIJyBUIJ6CVgXgJAQzBg+BAoJkCgxcBCYRIEPArlEH4YGDO4ibBeQs+AokAsAGF");
height: 32, katakana['NE'] = image(61, 55, "AAX/4AGEg/+Bws/+AGEgP/wAHEh/8Cwt/8AGEgf/Bwsf/AMEAAYnBj4GDHwQOEDAMHA4hVBn4WFJIIADHwMPA4hgCAwZkFCQKCGBwpHBPQwOFFAJyGBwt/BwozBBwpwDGYiYEEgP+iAkF4IPDCoP8j7WCUAXhbwYVB/4RBU4n4QISfD54vBS4f+FASPD+AEB+AFB/IjBFIPnA4LzCGAfAeYIjBGAP4eYQCBwZuBeYUH/EfIwJRCAoIDBg6ACnCmDR4oqBDIKfEHgKuFS4g5CBwo8CWwqOCAAQ8DcYg8Vn48FAAo=");
bpp: 1, katakana['NO'] = image(47, 52, "AAcHAokP/gFDj/4Aod/+AFD//gAgUB//AAoUD/4oE/woJn4oLEQYoBwAoIh4oEj4oFJZ8HERU/EQhFEDgIiDH4JFDh4iEH4t/NAYcFHII/Dj4cEv4/DCwIcDCwIcDCwI5DCwhEBHIYQBKwf/GYYhBCwc/FoYKBFoYEBFoQKCE4RrBE4YFCHwQyBHAYnBJ4YFBcBN/AgcAPgYABA=");
transparent: 0, katakana['HA'] = image(62, 52, "AAP/wEH/gGCgf/gE/+AHCh4MB//AA4QMBCIQeD4ARCDwv4Dwt/8AeEgI4BDwkH/weFj4eEAgIeF8AeEAgQeEAgQeEAgQeEAgQeGMggeCMggeCQYiACQYYbCDwgbCIogbCIoZZDIoYTCMggTCEwn/CYJFDBYZFDBYYmDv4LBEwYDDg4aCh5JCDQYiDaIQWBNAQ5CMAYLDcgYmCCwgqCGIYTBFwL7EJIIWEAgPgh4WDNAPACwgMBCwiHB/wWEFwV/CwZVB/YWEDgPHXgYuBDwLbDKQPwh60CGwWAngGDgAFBkAHEsAFEAAQA==");
buffer: atob('AAAAAAAAAAAAAAAAAAIAAAABwAAAAOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfAAAA4YAAA4CAAAAAgAAAAIAAAACAAAAAgAAAAYAAAAGAAAABAAAAAQAAAAIAAAACAAAABAAAAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAA=') katakana['HI'] = image(47, 51, "//AAgUB/+AAoUD/4QDg/+AocP/gFDj/4Aoc/+AFDv/gFw8BwIuDj+DFwf/FwcP/4uD///FwQKB/wuBJwIFBFwM/AoP8//PAgP/+IDCAAJdBAAXwg4FDEoQKCIIIgCLoQFBKYV//5qDB4aMuF1YFDFwIRDUIQAC+YFE8YFE44FEw4FEUgn+Aon8WwhKBXggA=");
}; katakana['HU'] = image(49, 50, "/4AEv4FE34FE74FE94FE+4FE/YFE/oFE/w0Dg//AocD/+AAoUB//AI4ngAod/+AFDn4FEj/4Aon8AocPAokHHgg2BHhYFDHgJCLJBZCEAopIFAoxIEAoxOEApc/AojSBbwplEAoZxBAocPAojICBQhBCGYIFDBYRZCa4P/NYQuCPoYFBSoZGFZYsPAgYABA=");
katakana.E = { katakana['HE'] = image(61, 43, "AAMH8AHF/4HFh//wAOF/wOG/AHEv4eFg//DwoOBDwgOCDwk//YeEgf/x4eEn/8n4eDgP/4AeEj/8DAIeCBwPgLgkfDYIeECYQeDh4LBIwIeC//wDIIeCBYJdCDwV/BwIwBDwIOBCQYeBn4pCDwRIBIAQeCMIJPD/AOB4CED4BhBMwf/MISbD/kHPovwj4ODDwV/UYhYBKQJ2DRoIGDHQINEcARCCWYgGEDwIOFgb+FDwL2EDwQGFIQoeCBw0YA40AA==");
width: 32, katakana['HO'] = image(61, 54, "AAV/8AGEgf/Bwsf/AHF//AAwkH/wOFn/wAwkB/+AA4kP/g8Rg//AAngv4HFCYIAE/EfA4vAAwv+Eo3wn4HFwAGFJwZ5UgfAPIJzDn/x/+PEgR/BAoJzDP4N/8JzD//D/6KDFYI8BCwYrCCAItBPQOH/wWDCgIQBCwf/4P/wIWCCQIBDWgYBCZ4KJBE4LPDEYInBh5sBBgKLBNgQ0CJoIWB4ACCBgIiBBwP8EYU/TQLXBHQQECFAI8BCwIqB8DzCDYMPAgQbCMoI3BF4IRB44OBWwQUBv4TBJIV//InBHgQCBw4OBHgUH/EfNgKOCj0A3BsCQwNgeaSdCABA=");
height: 32, katakana['N'] = image(54, 50, "ggGFngFEgP+AwkPAws/AwkB/4GEh4GFn4Gaj///gNF/AGF4BEJAwITBgOAAwQTBh4GCnwJCCgVwLgRwMHAgTBHAgTGv4TEgYTFMIITEMAsHMBY0B+ClFCYiPFEAITEv//OIQMCTg3gBgggEDIIgDGYIgDMIJVDDAIABIIILCFoYYCJwZ0BHQgsBBgZnBBggnCKgYhBMIi3FgAFFgAA==");
bpp: 1, katakana['WA'] = image(51, 50, "/4Ay4A3E/AFCh4GBAoUBAoPgAwU///8AoUHBgOAD4nwAoUf//+AoUDGRYSBGQYSCGQd/94yDh/9GQZFB34yDn/zGQcPAgYSCG4YSBC4YSNv4SKJYJwDLwISEn5QDS4QSDDAJjDDAJ2DGIJ2DUYQ+DQYKcFFYYXBDASOCGIQFDGIQRCDwTaCG4YFBEgbHHN4hiFg6HEA=");
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAJXAAe+20ADRQAAAAOAAAABgAAAAQAAAAMAAAABAAAAAwAAAAEAACABAEAgJbvgP9qSsByAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=') katakana['WO'] = image(50, 52, "/4AE34FE94FE/YFE/wYYGocB/+AAwd/8AFDn/4AocP/gFDgf/KovADAnwDB43B45EE+IFE/F/KAkfBgmHAonhAonwDAn8h4MEN5X/N4l/N4k/KwkfRwgoBDwcHOohoBOoYFBEgY2BEgYFBEgYFBJIYXBFQYpBFQZ3CAoIWCKoQQCGwQLDHgR8CAoQdCAoQvCOYYFFn5gENgKREbYgAGA");
}; katakana['RA'] = image(51, 50, "n//AAcHAongAon8j4GEwYFE+F/Aof+h4ME4IFE/BYr+4FE/wFE//fAon7BgpYE//vAon9CQo3Ev/gAocP/gFDgP/wASX+ASJgYSFXwJ2ECQivBDAoSEWIs//wFDbYIrDAoI+DAoIYDQ4IYCFIIABDALlDGIJhBewS/EJQQYCG4YkED4QFDD4JJF4AFDA");
hiragana.E = { katakana['RI'] = image(43, 53, "AAf/7/4AgMf/f/AgMD/9/8AFBv/v/gEBh/9/+AgEB/+/+AKBn/3/wEBg/+//AFX4q3v4qDh/8FQQPBz4PDAYQvBEYQvCEYI/CGYRPBB4cfIYQpBB4cH/5TCDwJjD/4kCn4EBCgN/AgIUBDoP/FIJHBAAIyCDIYjBIYYaBQ4QaBJoZHDAAoA=");
width: 32, katakana['RU'] = image(61, 53, "AAUH/wHFn/wAgUB/+B/+AA4UP/gBBCgd/8ABBAwUD/4BBBwcf/ABBA4f/4ABBHQg8FHQI8/HksYHgwYBHgkPF4I8EvwlCHwOAg4gBEYI8CCIQjBHgITBCIP+HgU/CwIRBDAIgB4AMCAgMfEAIMBDAIOCBgQYCIwQMCPYJTBAQI8BBwUHEoN/8P/IYN/+AvBj4LBBwOAj/7BwZGB/4ABBwXAAQIODM4QOFHgIOC/4OBh4OCAYJGBv4OCn4OBHgJKBAYJkBIQISBaIYhCCwIOBSoTqBJQISBeYUHd4U+bYUwcAYAKA");
height: 32, katakana['RE'] = image(51, 51, "//AAocf/AFDgf/CQl/8AFDh/8AocB/+AAwc/+AFDg/+GX4ECgwyEgPgGQk+GQkP+IyDC4IyE//3GQc//gyDh//GQYYB8YyD//4GQc//wyDDAOBGQUH//gGQRvB/BlD/4DBGQU/CwIyCj4YBMoQkBBIIyBBAIYBGQIkBDAIDBGgIiD+AFBGoIyBv4eCGQIABJwQvBAAJnDEgTLCEgY8CIYLLDEgZVCAoZuBb4iaBfAj+EgE4AokAA");
bpp: 1, katakana['RO'] = image(50, 47, "/4AEn4FE94FE/YFE/wYF34YS4A1BgIYB+A8Cv/v/gFCj4YBAoUHDH4Y/DEbglDBQ8CAAYA==");
transparent: 0, katakana['YU'] = image(59, 46, "gP/AAX+A4M/A4fggEHAwf8BwIGD/4GBj4VFgYVGv4HDwEAh4GD+A+Eg46CAAf/4AGEj/4Coo6CCqJFBCot/KAIADh5QCQAhQBCrM/Myk/M3JQGh5QFMyIRBAH6NB");
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAADgAAAAOAAAADgAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAdwAAAcYAAB8MAAAIGAAAADAAAABgAAAAwAAAAYAAAAMAAAAGAAAADIAAAB4gAAA4EAAAMAgAACAOGAAAB/wAAAAAAAAAAAAAAAAAAAAAA=') katakana['YO'] = image(50, 49, "v//AAefAonnAon5Aon+DDA1DgP/wA8E8AFDj/4AocHDFZjfDCJjxDD5WE/+/AonvAon7PgoYX/g3DAAQ");
}; hiragana['A'] = image(52, 50, "gEB/wGEn/AAocD/gMcg//AAfgv4FD/wMYFIRNa54HDgYyCBgYsEBgX/+AGBHQYpBCQQaCh4JBJQPwgIdBBAP/wASB4H/j/8MIP8j5fBBIP/4P8gf+j/7/hVBj/jA4PH/C/Bn4RBv8Aj/3/Ef55FB/9/wI+D+/wj40BHwIWBL4QJB+BFBwAmB/4MBD4M/94MBD4JAB/4cBNYN/BgM//AsB/n/z4bBQgOHX4QVB/B3B/CQCAQTSC8BFCB4Q4CB4UAgIIBRQOAXojREn/gaIgAC");
katakana.O = { hiragana['I'] = image(58, 50, "v/gAgUggEf/AGCnkAg/+AwU/gEB/+AAwQZBDgcP/gcECQIcFCQIJCCol/4AGBgYLBj/wCokHCAIABFAIQCCon/DgQECn4cDCoItCAAI+BDggVCLoZeB+BgCCocPPQZUBwZdDJAQcEGAIcEGAIcEGQPDDghIBDggyBDggyBx4cBjxIC8aaCCAIyBLAMDM4IyBSARnC//HUIk/+IyBCASdBLAJKCGQOf/kDJQV/GQRKCJ4XgEYRPC/CoCDgOHNwl/8P/84jCDgM//5HCDgMHAwIjBgP8DwIsBQgYVBSQgVBaYZnCTIgtBbQhDCUAYkCfwYOCGIgAHA");
width: 32, hiragana['U'] = image(46, 50, "h//Aoc////8AFBAgIABgEDAofACwIAB/wWD//4CwgdBCIeAFQUfCwIADCwIAMj//+AEBv4tDAgQLBHAYFBAgf/8YFE54FECwRTB/wkCAoP7IAd/OgR2CKwcBQ4kH/hMEJYQcC4AWIh4WEn4tJg6EEj6EEVgIQDE4l/CAbABCAZqBBQgQDBQIQCXwIyCYYTIFeIhlCBQjxCLIQWBMgbdFvzYJ");
height: 32, hiragana['E'] = image(55, 50, "gF//4GE/4AB+AFBgIGC/+AgEDAwYNBg4FC/wGBh4GC/gGF/ArFFIQAD4BRVn42FLAIGEJQYGBLAhEBLAhEBLAf/8ArDBIIyEj5fCRYZYEEgJYEN4JNFDQouFDQKcBFwYGFMIIGDLQRJFAwgaBOYQuC8Y2DFwODAwcP/0HXAc//EPcQnAj5LCPAU/MwR4Cv5ECPAQ9CLoUBd4auE/guBVwf5PARaC+5qCAwXnJwSXB//HI4QGCw5ACAwUHNIn+gj/HAAg");
bpp: 1, hiragana['O'] = image(54, 50, "gEB/0AggGCg/4gE8AwUf8EA/gGCv+AB4QaDv/wDQn/CwIaCgP/4AaDgf/wAaCgPn/4PBAAXv/0HAwef/kfAoX+n/4v4GCAgPxCYfg/4jBAAWBGwQ1BgEDJoJQCJoJRBLYcPCAJrCgEcKAaGEHgSGDF4QPCJYYxCHoYMBn5YDBgoGBDIP8FQKiBDwabBFoIzCv/gEAJQCMwWfKAIbBh58BDQMH/l/4IaCh/xTgIaCn/P/BrD/8/4CGD/i3BDQfz/gaDv/P+AaCCAIaEHQQaDv/hGoV4h//g4VB8JnBa4ePZYRkBBwKNCbwPwCYR/C44CB4BtBfgSaD8ACBYQQWBAAYA==");
buffer: atob('AAAAAAAAAAAAAAAAAADwAAAAOAAAADAAAAAwAAAAMAAAAjAABAAydAbff/wH/XAUAwDwAAAB0AAAA7AAAAMwAAAHMAAADjAAABkwAAA4MAAAZDAAAMEwAAGEMAAGQzAADAHwABAA8AAAAHAAAABAAAAAAAAAAAAAAAAAAAAAAAA=') hiragana['KA'] = image(55, 49, "gEH/AGEh/wAwkf8AGEn/AAwl/wEAhgGC/4CBngCBgP+AQP8AwMDAYIyDAYUPAwQ2CAwY2Cj/4gP/AAP4j/wgYGC/gGBg4GC/0/8EPAwsfCgd/4E/Awt/FIf/LgJmBE4IGCMwMf8JjBHwIPB4IDBgZmBv+DAYMHMwP/BQRfBOwIKCL4J2BOIQvBAgJxCGQIEBHAKPCCwIYDCwQBBQoRGBviIDIQJRC4AdCXAYdCKIcHboQ/CboY4BboghBboZKCFAYhBjAoDh/8nzME+CfBF4V/RgP/EgKVBwYGBFAMH/zIBFAQeBAwIoDboRRD4DrBJQUHAQJsDAAwA=");
}; hiragana['KI'] = image(48, 50, "AAMB+AFDh4FL/AFDg4FIn//AAX4ArpHC/xNEAov/LQgFCDgYAlF4UfPx8/g/8CoQbBKgQhCAoMDFAkHAoeAh4FEDgQAB4E/FgIUBwE/HwQdBn/gAoM+AoPAAoMMAohFCAqIpCgI7C4BEBI4oICAoZfE4C9BAob2EAoISCaQgACA=");
hiragana.O = { hiragana['KU'] = image(33, 45, "AAsB4ADC+ADC/wDBgf/wADMg//CYIDDh4DDD4UfAY/8AY34AZRDCh4DCg4DCgYbCgI/CgH/BgU/BgREBBgIQB8AMCFIRNDLoJ2Cv42DJwQdDFQIdDFQQdDFQIdDHYRkDgYhCgADDnwDChyzE");
width: 32, hiragana['KE'] = image(50, 49, "AAUB/0Ag/gAwN/wAICgEfBIIIBB4P4BAYPCh/wDAcD/gYE/4FBDAU/4AYEGIgOCDAQOBh//AAP+v+DAoX/7/AAof3+E/AoX9/gYD/9/gYFD/4YE/5QCGIJQDHYRvCJQU/N4JKCKAYYCKAQYWmAYEjwYEx6lDh/zUocDMgIYDv6cBKgUf/4yBBAMH/4eC4EBNQUfAQN/DYMPE4TjCAQQkCYgSJBDYLEBn7QCAQIbCE4UDDYP/PIV/CgLpD4EPP4UH+AkBAoIACCgIADh6LCAAMDAoYA==");
height: 32, hiragana['KO'] = image(52, 50, "h//AAX+gAFD//gBgn/BgvwBiWAAon4GwUBDIQACCQQFCn//4AFCg4lBCQc/DwYfBKQJdEDwYAB8CIihAFEgJJDIgQFEg5KEMgITEj/8D4hwED4JqEOIIfEv5eEg4fEFg0PHIwsEBigmFCYkOv65CJYPnbgn+ZgIAD8IMFewvgCYjRBE4IMDegQABIoUfAoK7HA==");
bpp: 1, hiragana['SA'] = image(51, 50, "AAMB/gFE/+AAwcf+AFDgf+DIl/4AFDg4fEgAfLgIfCj//AFQzCn/gLJYMELI5mEh6GGBgUHGAP4CAQ3COYILCBgUDIgYZBAoYmBn5REDwPgQQPgDAIVBj4fBJ4d+CQI1CgeAXhgSDKoYSEQQp1GQQpFBawXwD4IGBg42BaQngBgRlDBgmABgjzBRYZDCPIYvCv//MQoACA==");
transparent: 0, hiragana['SI'] = image(45, 50, "v/AAgUD/wKDj/wAof/wAECg/8BQc/8AbD/4bE/AbEFgcHFgk/FgcBFgkPDYhIgFgIKDFh8eFgn+FgcH/4sDv+/FgUD/osDn/vFgQ2BFgcf+YsD/+fFgUP/gsDv/HFgSKBLId/8IsCHgIXBSod/EIIKBwIhCv/4h4WBAQOAv/+IIP8AQIAC4AYBAAIkBn4KDJQIKDCwYpBCwRWCAoJhDAoK1DAAg=");
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAgAAAAMAAAADACAAAwAYAAMADAADIAQAA/AGAF+AAAAyAAAAAgAAAAIAAAACAAAAAg/gAAJwOAADgBgABgAMAAoADAAyAAwAIgAMAEIAGABCADAAJgBgAD4AgAAMAAAAAAAAAAAAAAAAAAAAAAAAA=') hiragana['SU'] = image(52, 50, "AAUf8AFDgP+BjH/AYP/AAnvAon+BjJAUgf9BgZFB/4MDn4kEg4MFGIwMED4QME+E/+AyC/x0DFgPABwIMC/gMGDIn8gYMFv/4EwcP/+AKYf/BgRACBgYRB/4mCgF/AwJ6DBgoTCRohNDTZE/VAkP/gFDE4PAUQhGCI4YeEUIgYBD4gMBEpI4GgIFEAAo");
}; hiragana['SE'] = image(56, 50, "AAcP/ADB//AAwP8AwkHA34FBAAn+A1JalmAGFvinFv4GF//PXghEBAwfBAwoNGEQP/+AGDn4GFh//8AGDg5PCgF/AYP/wAGEgj/CAwQADAw4mCAwZCCAAQ8BFQgGBAAQGBj4GFJQIGEJQIGEgYGFGIIGCIQQVDHQgACA");
katakana.HA = { hiragana['SO'] = image(53, 50, "gP/AAXggEPAweAgF/AoX+gEDBgfwgEfCYoFD/EAg4MFAAQMCAAQwBBhQpBJQozBAAU/IAIACIYJUBAAV//gsJD4IsEn4sEOAn+NIn/+4FEAA39AwvvAwqQDAAP7UYhmCx5bDuBVB4BCDg5bEJ4JoEgJ1EEQKCESwIFEg5vEEA4TFh4TFv4TGYgiLBCYrFG/5dDd4YHCOQKkBDQjbDDQQwDWgR5DAwSGEEAgAEA==");
width: 32, hiragana['TA'] = image(52, 50, "gEP+AGE/4Mjgf/AAXAgE/AoX8BjUAgP+GYkf8AFDBhHnEIQMBEQQhBn/jFAWAgYMD/AMH/gMF4f/F4UH/kQGYd/KIIACg4VBBgmAQ4gMFUJcB/8DDQZgBv6iD/wuEn/gKIJGDEIl/4KCDC4KPE/+BBgYXBBgY5BAIImCj4MBTIKFB/wMBAAKSB8EPAwXnUYIMDCwLYD95RBEAIZCFQN/AwPBKISpBwEGQAgAGA==");
height: 32, hiragana['TI'] = image(51, 49, "gED/wGEv/AAocP/AFDgP/CQk/8AFDg/8Bgn/wAFDj/wBQYAqJ4M/LBZrMJYZ+Ch5aDv/f/4bCBQIABCoMDHAYTBv4+Ej4MEg4DB4IMCAoIcCwE/TwU/+ASBEQI8BVQJLCv/gS4cP/kBMgYWBjyoEgLbJEYYSCQQkHCQg2EHASCEv4SBgYOBOQ70BQoYrBEQIABFYR/DJASRED4YFCBgJDDA=");
bpp: 1, hiragana['TU'] = image(59, 45, "AAUP/4FFAAIGCAoX//EAg4GD//ACYYAB/kBAwgOBn4OFDgoOBAYX+BYP8j4GBwEAAgPDGwQ+C/F/BgIABCwOMLQl/+AGEg/+NIv/8BwF/gGEKwIqDAAM/HAYzDEhkfEgsDEgxJGh5JFHQPACqQrBCpkfCopXBCogcBCog5BK4jSCAwxtDDYK8EZIQcCAoQcDCYTjCJgQGCEYT0DIAYGGEgQGDEgRcEv5UEA=");
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABIAAAAcGAAADgwAAB4HAAA4A4AAMgHAAHAA4ADAAXAAwAA4AYAAHAMAABwGAAAMGAAACDAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=') hiragana['TE'] = image(57, 50, "/4AFv4GF34GF74GF94GF+4GF/YGF/oGF/w7Cn//4BCDAwOAAwpQEj4ZDAxP8AyUPAwwiFg4GMgZFFAw0BLQqlBNAkAv4GG8AGEn/wKgv4KhZGGHALeGH4oxNh4xFOJBjGEYt/VQwVFg//BwhOBAAI7Dv4GBHYYcBCwgcB/5CEDgQyFGYgrCUwkPKAwAC");
}; hiragana['TO'] = image(46, 49, "gEH/AFDj/wAod/4AECgP/Cwn8C0cICwcDBoIWC/4NBCwMfEgV/4f/BoIWBv//LAMH/4AB8AWBAoWAgE/BQYlBDYUAh4FBHwQPEEIJQDFYJhCgYwCLQQqCDYQKDDYIKDn5xEEAYQB/x8JDYkDCAkPYIk/JoQWTAol/AocZQwR6B8aNCAAOPAgf+TIZqBAongT4QfCBYY9BW4R1BA=");
hiragana.HA = { hiragana['NA'] = image(55, 50, "AAd/wEAn4CBgH/BIXAgEB/wJEgf8AQIJCg/4AQIJBgEP+ACBBIMAj/gAQYsBEoIoCGwf/GwkB/8P/4AC4f+j4GDw/4n4GDj/wv4FC/0/8AMD/l/4IGD/H/wYGD+P/g4vELARtCMQRtDMQQKDL4YKCMQQKDMQQKDR4QKCTIYKCFYQ2bOoI2C4BgCGwWASAQ2BGQKJC8DNBBAIAB+DNBPYf4ZoKrDAgPwT4K7BAwRdBB4K3BVYIqCVYY6BAwKrB/0DVY3+v/hAwf8n4SBdIXwnxEBAwXgnBEBAwShBO4IbBSYSVCOYQAHA");
width: 32, hiragana['NI'] = image(57, 50, "AAMPwAGE//gAocf//wgFwgEH////kH/AZBAwP+gf+Bof/wP/gEDAwWAAIMBAwc/FgIGDj4sBv4GBE4P8HAIdBE4IqBAwYgBKAIGCKAYKBAwN/EYIGDn4jBAwZfBDAQfBLIPAAwZZBDgItENYN/CAIfBIAIGCLIRfDLIXwAwc/RQJmCHAPv/0PEoI4B+f/AwcH/P/w50D/l/wZ0CgP+j/BK4Q4Bg/gJoQ4BwIGBIwU/4EwAQI4CIYICCAYY/EJQMHHATcCbAQKEHARGBGgQqBCIc/D4IGDaITCDT4PAAQJfCQQRYDeQQGDSIIGEYYIGEE4IGEDgYFCcAQ+CGQZsCABAA=");
height: 32, hiragana['NU'] = image(58, 50, "gEP/AGEgf//wHE/4ABAwc/AwIPDh4OC8AGBg4GCEwUBAwX8Dod/EgoHC4AsF+BJFjAGDg4iEFgRfF/+AAwk/IwQjDFIgjDvAjDMYJlCgRHB4ABBFIUf/ABBFIXH/0HCoUf+BcBLwQpBCogpBCYIVDv+ACohNBn/wCoRxBCohNCMoIVBOIQVBAIJNCCAIVCEYIQBCoOAb4QtDCAQtC/gjCdIIXCN4QwBC4SVBDQIXBEYUP/gXBI4QEBHwPD/8ODgR/CwZNCCYN/8P/5/4GQOf+DtBKgXv/jtBKgX5/0PAwJxB/0/DAL8CvkDJYP/IYMMgFgg//fot/VYQACgYGFAAoA==");
bpp: 1, hiragana['NE'] = image(67, 45, "AAXwA43/4AHFn/8A4sPCA0B//+CAt///gA4kfCA0H/4QGA4IyFn4IBGQg5BIYsD//nCAt//F/CAkf/wzBCAYFBwH//BaE8ArBwBzFCAgNBLoQQCHIPADYIQD/6dBCAk/OQIQEHIQQEHIQkCCARaBO4YUCSYQQDHIQQFHIQQERQgQCLQQQEHIKBDCAPAn5fDCAP8gbNECAaJDCAbVECAPgvj+Gg72GdoqYFCAgHFKIoQDDA0AKIjODDA0ARYQAEhwHGAAIA==");
transparent: 0, hiragana['NO'] = image(54, 50, "h4GFn+AAocB/0IAwcH/F//4AB+Ef8IFC//A/+PAwcD/0fAoX8h/wDQk/4ITDAgMDAwcH/hGC/EAj/wIwXggF/4AGB/+AJIIFBGQJJCDQoWBDQf/wZlBDQIWBh41Dx5kE/0/Mgn4IgIGD8f8MgYaBL4IaEPQJrD/6RCGoRkCKAR/BKAgaBKAoaFNYoWCKIIaC8BKCDQWAIYQaCgJCCDQRyDDQRXDEoOBK4ahBW4K+CAgKcBDgLcBMwIwC/1/4JHBCYP5CoQwC4aND/atBRofDAgPgdQaSBHgX4hxXBHQXAhAOBAwKXCAAJlBbIIAH");
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAABAACAAYAAwAGAAMABgACAAYAAgAHwAIAD4AGAfYABAAGAAQABgAEAAYABAAGAAQABgAEAAYABAAGAAQABgAEAAYABAOGAAQEfgAFCA8ABggPwAYG+GAGAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAA=') hiragana['HA'] = image(50, 50, "AAMH/gFDgP/Bgl/4AFDj/wDBsH/4AD/oFE/9/AwoARJVXhAon4JQn+j4MEw4YLn4YEJTIfCAooYCAoX4DgQwCwBdEBgMDHoYMB//3Bgd/8AUC4A7BJQP//kHBwQGB4JYBFoX8KgMP/gGBz/+h//AIPjGAXA//wAoXwh/4DgX4gP8IgQnCF4QFBgOAEIKIEv6SCAA4A==");
}; hiragana['HI'] = image(59, 50, "gP/AAOAA4U/AwPwAwUHAwP+CwYVC4AGCj4GB/AGCgYOCCod/AwPgGokH/g8GHQY8CHQYVCHQg8CwEfCAYEBgYQDAgV/JYYEBh5LDj/4GoJKEGoJLCAwP4JYZ9C/BLCNwSGDQgSGDOoaGDAwg6BEYQHDh//EomDAIP+ToaQBEIIvCKoJyCJgPH/yDCEIIVB4BNBMwIgB+CZCn/n4f+h5jBAQMw/+BOgKyCCoN/PIICBS4I0BCoQJBJQJqCBIP5NQfgD4KACn5tDGQSDEwADBTIJaBGQKZEDISvCToR8BeAQDBAQLbCb4RSCAAcHcQYACvwGFg45BAAj/DAAw=");
katakana.HI = { hiragana['HU'] = image(55, 50, "gED/gGEg/4AwkP+EAhwGCj/ggF+AwU/4EB/wGCv+Ag4GD/4kBAwM//4AB84GBv4GC54GBAoX/x/+gIGDh/+gYFC/0P/kHAwX8AwMPAwX4j5cCGwJOBAwJIDj5jBv4QCAwIpBNoU/+AiBNoIGCJYJtBAwPhFwPANQXjAwOAgEEv+P/A2C/H+CoI2BTIIhBwY2Bh/xwH+UgUf+CwBUgSgBBYKkCn/gh/gToI1B4Ef4AvCBIM/4ZmCIAN/44oBSgKdCFAJ3CLAY0BUgQoBGgIGBEIUPAwSID+AGBQIZHBJQRECd4Q9DI4QvBJwQ2Cj4sBGATRBJwLcDFgTcDC4QGEEILqEAwIbDIARoCBgQAGA=");
width: 32, hiragana['HE'] = image(55, 50, "AAUf+AGEn/gAwl/4AECBQP/wAYC4EB/4YDwED/wYDwEH/gGCCIMP/AFBgIRBGwcDCIN/GwUH/EP/4bCDAP/AAI2C+4GCHwMfAoX/JgM/AwYjBv4GI8YGCFoN/wIGBgYCBFwIiBHYJfBNAPAn/8IwIGBwAaBh/wAwOD//4R4IfBg//+B2BDoJKB+AoBg/+JQPjOwMP/n/z/nQIMf/IOB76BBn/3/gVBMgN/94nBOQX/7/gAwKbBOwSOCHoJMCEIMH/v/CAJxBh/7/hcCF4X4KYLEC5/wj5KBEIOfGwJRCL4PzF4V/JIQvBCYJJCH4JxB4AGB/xCCFQIJDDoIMBBIRNBAQJdCIwKUCeAb5CPgQACSgIFDSgIFEAAg=");
height: 32, hiragana['HO'] = image(51, 50, "AAN+AokP+AFDgf+Bgl/4ASE/ASVv//AAX8h4FD/+BAonwn4FD/0HBgnAAogoBgP/HAk/8AFDg5LEgASM/gSFwADBFQIAC8E4Iof+/5FE5/wAof5/0fAwc/8YFD8f8PAYEB54MDJ4SRDJ4KRDj/gNYaoCLAYWBLAYWCLAQWCDYJvDgYSCCwV/NYQWBGQc/+AyDg4yBj4MBgYSBAQP4OwPwbIglBQAgpBBgZiBBgYYBBgY1CU4S0DFoIRCAAo=");
bpp: 1, hiragana['MA'] = image(55, 49, "gEP+AGEj/gAwk/4EAkAGCv+AgAPD/8AgYdCgP+EgkD/gdB/AGBg4DBv4GCj/w/wGCv////8AwQFB//4AwMBAwXwEQMDAwXgAwMHAwXAAwMPAwWAG4QvBLgQGBL4X/AwRfBKgIGCL4X8n/gLARUBn5YDMwM8NQaLBQYIoCAQSIDAQRZBRYaBDRYQhBFAIJCKIYyCDwKoBToZkBOAIJBPYKLCGwMH/h2CAwMfKoKKCI4PgSIYYB4afDJQMP/gpB+AhBMgIjB/AhC4EfAwIhCEoIGCwJdBaIIZBMgSkCjhMBgakBG4LICUgKDBAwQuBPgRKCjgGE4EQAwgEBAAIbBRAQACQgIDB");
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAXAAAABwAAAAYAgAAGAMAABgDgABYD0AAWF4gABvwAAAfAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAgAAal8AAD//gAAJQAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAA=') hiragana['MI'] = image(50, 50, "h+AAocD/gFDgP/CQl/4AFDn/gv//AAOP/E/AoXj/0HAoX4/+BAoX+DAuf+EfAoXn/gYD/P/gYEBG48f+AFDg5QMMYkf8BvE/BvE/wYE/4YEKAIYYgZSCDAMBJgQYCCgYDBFoYDBj4tCDAJlDDAMBGYYYBNYYYBn4xCg/4h6ECPgIHBPgfBDwaVBQgYvBToYYCFYauBaIIwB5/wcAfz/0PAoX8cAn/IgQFC55dBAoXxFILtC/grBGgL5BYIoAGA==");
}; hiragana['MU'] = image(58, 50, "AAV/4AGEj/wAwkH/gGEgP/Aod+Dgv/wAcEj/gDgkH/AcEgP+Dgt/Dg3wn4mBHwYGBDAIyCAwP/8AGBAoQODh4GC/4sBgYGD/AcCAAO/IQQcC4IkCDgI7Bj5YBg//w/8EAIjCwIEBv/gMQPgLAMPFYP//h1BgZpC/4LCNwIxB4YoBFoIxB/AjBNIMH/v+n5UB/4qBn/fIoIJBv+PLYUPQwPhOIUD/gvBGYMH/3/BAX/457CBAP/84GBDgIlB/YGBCYJwB/qECDgKREwBCC34YBDgfvLYP+HIM/+YYCIwM/MoIYB/hGBMoQEBz4nBKQfDAwODGQXwKQQMB/P4j4GBAQP+ngtBUgIRBg6aBRwKiBwOAf4TNBAobjCAogAEA");
hiragana.HI = { hiragana['ME'] = image(57, 50, "gEP+AGEg/4AwkD/gGEgP+Dgv/Awt/wAGEn/Agf/BIUf8EP/40CHAMf/4tBAYP4AQImBCIP8n4GB4EH//+AwXgEwP/v4CB/EBAYIPBg4jBAwX8BYJFBCQRKDFYIGBJQJxBIgUfAQIrBAYMPCAIfBBQR8CAwR8DMAZ8Cv4GCGIQGDGIU/AwR8BAwKqCWoU/FoS1Cj4tCHASEBWogGBUAQKBAwItBHARpB8BlBBQKuCAQIKBO4SqCBQX8AwX4h/9/wGC/kP/n/DYSlCv+P/ArB4K+B4/4SIV+j/jWIX8n0P+JSBDoMOMwJWBAwOCMwM//ZOCMwI4C75nB/5bC45nBv+DAwPhTgXAb4PAoCfCQQifBYoYAHA");
width: 32, hiragana['MO'] = image(60, 50, "AAX//4GEv4HFj4GB/wGCg4GB//4AwMBAwX/4AcEDwcPAwYWBgYGDCwQVC54tCCoX8F4PgFYP4CYI+BgE//0P/gaB/ARB4F/4ApBwAVBg4OBj/8EgITB4AiB4InBBwQgBCAIOCPQPjD4MPJ4MH/0/+ALBwARB84kBBwQ0Bv/gBwc/+5bBj5tEHAR8Bn5lBBwInBBxY2CBwcDWIQOEGwIODJwIOFIoRKC4CNCBQP3AgKwCDIIOBKIQKB8/8IQJgBj4OB8E/MAfD/ytBEgX8J4KeBZwWDIgJCBCoP4ZgIzCAYIqBeYRQB8DnCK4gGBGoIDBwAyBF4IKCCQWBAwIVBEoPgF4RFBg/4F4Q2BAAQOBTwIADHoQADbIQAIA");
height: 32, hiragana['YA'] = image(54, 50, "gEf+AGEv/AAocB/4MEg/8DUv///Aj//wEDAwIcBAwMP//8BgIGBn//+IFBAwICB54GCDQQAC/0HAgXAn45BD4IDBn45Bv4MBAYPgGYJKCFAIbB8EAgf+DQRbEv/4LYYaBOQU/4EPCwIhCCYJrCgf8CYkP+BlBCYQaBv6GDOwQaECYIaEKwIaD4JWDgP+CYIaCg/4NQYTB8Z+BFwef+4aCMgN/74aCn/z/zXCIAOH/IaCh5CB44aBJoU+a4QyBwFwDQLGBCAOBX4adBGIJMBRIQaBUYI4CDQJnDFYJ7EDQKzCDQYECAA4");
bpp: 1, hiragana['YU'] = image(52, 49, "AAMf+AFDgP+Bgk/8AFDgYMM/gkD/4AC+EBAof/BkA5FhEAg45Cg/AgF/AQMBBIMP/4DB//gE4Xwn5dBn4GB74IBgY0Fv4FD8AfBAoYfB/gbBIAIiBg///A7B/+A/4rBCQIxBBAISB/ghBCQeBEoIMBCQI0BBgQSCDIYSB54MBgIlB+AMCj0H/0PBgIABHQQMBOgP4BgZBBBwTDCMYIMDKIIMRWQQmDAwUMYYqyBAoaxBN4IMEV4QMCcggMBWwbZCAweA");
transparent: 0, hiragana['YO'] = image(55, 50, "AAMHAwsP+AGEn/gAwl/4AFDgP/BgkD/whF/AGEj4oFEIsA/+AEIgoFg/8EIooFJQ3/JRcHJSgoGJQxEEg//FIkfAws/Cgv/AwUGJQX/HwMP8AoB74GBj/gh/+IoU/4BzBBQJBCJQIKBNQRzBv+AWoIIDJAP4SoMBIgIkBOYMDHoKTBAIIRBXgQBBB4IfBEIQYBFALgCCwMP/iVCJAXwJ4QfDcAX/4JRBSoRvBEIZ2DcAQGCFQIhBPoIYBcAQGBDAJqBCgQ6Bg7rIAAY=");
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwEAAA8BAAB2AYAABACAAAwAQAAIAEAAGAJgABACIAAwAjAAIAIYACACGABABAwAQAQEAEAEAABADAAAAAgAAEAYAABAEAAAYDAAADDgAAAfgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=') hiragana['RA'] = image(48, 50, "gEP4AFDj//wAFE/gFE/4TCn4FBBgQFCBgQRC//gBgN/BYUP/EBAog3BGIIFCgH/BAIFCh4FEgQFEBoXwAqsfAoIuBAoROBEwIFBIwP+AoPnLIWALwZfBNQf/+AFE/AFBEIM/AoR6Bh/8OoIzBg4FBRgQFCL4UD/wlBAoikCAoM/W4QFBj5dCAoMGAohpDg4FEHYJ1EAog5DDgJWCb4Y/Cg7RDaARFCAoZFBAobiEeoruCAoQtCAoI+DAAgA=");
}; hiragana['RI'] = image(40, 49, "ngEDn/AAg9/4Ef/AEBwF//4EBwP//4HBw4EB4F/x4EB8F/z4EB+H/n4EDAQIjBCwUPAgUAAgX+gEH/n//gEDHIMDAg3wAgP+AgvgAhBeBAhmAAiJ3BAhf8AgRUBAhBXBAAJtBAgSgCVgRcBAAJXCEwIEDj5SCBoJDCBAKSBBASSBXwKICAgQmCAgIcCv4SCAgI0DeAY=");
katakana.HU = { hiragana['RU'] = image(51, 50, "gf/AAXAgF/AoX8gEPBgeAgIFD/EAn4MEg4FD8EACQoACn4lBAAUf/4FDDYOAAoQuBHwIACv/wDwgkEh/+DwoFDDw5ECDwRLDMwg5BLIZMBNgh/FGgIeB+AVB4AeBEYJmBBAJQBDgPBOocf/AoCVIU/Kwc/+5WDg/+Kwl/5/wh4mBh/4/A2CFgMOAoJDC8GBMgUHGAJQCCQKpCBgISBgf+SQMPCQN/4H/4YSBGIIwBCgMBDoTMCn/AEIROCLoKFEAIJvBTwZvCTAarFNIQFCXASyCYoYxBAoYAEA=");
width: 32, hiragana['RE'] = image(56, 50, "gEf8AGF+AGigP/wAGDg//GYQGBh//C4M/AYICB/AGDv///gGC+P/AwQKB+YGB/wNC+//w4GDBYMDAwn4AwQ3BFQIGF8AGF4AGFgAGEAYMDHwIGBAYIGDn5XBAwhlBAwd/Axh6CAwSPBAwMHAxEDAwqdBAwidDAw5IBOoQGDU4QGDUAIGE//fAwufCgrmCh4iCAwk4nwGE/EcAwbSBjAGFegReCUgIGJOYIUEQIYGCIYOAAwPgAwIAIA=");
height: 32, hiragana['RO'] = image(50, 50, "AAf4gEB/4AC8EAv4FC/kAj4MDwEHAofwDAgSBDAoACn/+AocfAokP/4FDE4OAApED//AAohJBAAI5BAocAIQIFEHghFCD4QFCBoU/KIQMBNQZ9BOAhOCQYYFE/B8CE4QFBM4JGB4YuDj/7AocD/xIE/+fP4c/84FDh/8QoZyBj5mE4aFDn5yEDAIFDGIIFDIgIXDDwKREv4eEv4eBiAFCDwMH+A8BIQLnEEgLnDSooqBQYQFCDgQ2DAoolCJAgAD");
bpp: 1, hiragana['WA'] = image(51, 50, "AAV/4AFDh/4AocB/4DBj/ggE/AQMD/0Ag/8DgWAgH/AQMP+ASB//AgISBAoIDC4Ef///+ASBh4FB/4SBgYFC+E/4IFC/8H/F///9//g/8f/3/x/+j/nAQPwv/j/H/wf+I4N/KAJlBv+P9/4MoMP/f9/xlBAIIqBwAUBn/vFwIdBg40BNIIOBIIR7B+BbC8B7BKoX4uAyCAwM+GQX5//f8IyCn/z/hHCK4N/4/8h/8/4EB/4lBF4P/z5wB8f+RYJjBPoPAFwO/BQP4IQX/wJkCTAUfVYf4gf4BgS4BbQRiCcgbSCAAILEcALkCAAM/DoYeCC4ZLBfoIeD/ASEDAhoBAoYlBDwcAg/ABggAEA=");
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAAAALwAYt/vAD/0DwAcABwAACAcAAAAGAAAADIAAAAwAAAAYAAAAOAAAAGAAAADgAAAAwAAAA0AAAAaAAAAOAAAAHAAAAHAAAAHAAAAGgAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=') hiragana['N'] = image(54, 50, "AAVgAYUP8EHwAGCv/Av4RD/8D/wFCgf8g/8DQf4j/4AwU/8E/+AaDwF//4VBgIfB/4GCD4MPAwcf+YFB/4jBn4FC/4jBAof/4AYC//n/+DBYeD/wZC/f/FgIrCGIQsCKYU/444CKYP/z4xCvxOBv+/8EBQQP4B4KFCCoJeCNIYPBQgQKBj53CAYSbBCYQDBHgJbCTYUDOQZHBM4QTBTYX/GQQxBP4Y8BDQRGBTYY4Eh5MDHgZTDAojdEbAYGEHgIGEv7/DHgIhFfAh1EEIg8GEIg8GTYYhDHhYAF");
};
hiragana.HU = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAGAAAAAwAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAACAAAAAQAAAACAgAAAgEAAAMBgAABAYAgAwDAMAMAgBgCAAAYHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.HE = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAANwAAAGHAAADA4AABwDgAIwBOADcABwQeAAHgDAAA8AIAADwAAAAeAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.HE = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAIMAAAMAgAAGAGAADAAwAAAADAAAAAYAAAADgAAAAMAAAABwAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.HO = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAEAAAADQAAAAYAAAASAAAABgAAAAIAACAGK4A273dAHoYAAAAGAAAAAgAAAIIQAAECGAABAgwAAgYGAAIGAwAGAgGADAIBwBiCAaAYRgDAMDIAgAAeAAAADgAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.HO = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAQB+AAEAgAABAAQAAQAGAAIABgACAAQAAgAHwAIAD4ACAfQABAAEAAQABAAEAAQABAAGAAQABgAEAAYABAAGAAQBdgAHAg4ABwAHgAIB+OACAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.KA = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAUAAAADwAAAAcAAAAGAAAABgAAAAYFABAOvwAfv9eAD6wHAAQMBwAADAYAABwGAAAYBgAAGAYAADAOAAAwDAAAYgwAAMgcAADEmAAFgzgAAwHwAA4B4ABYAcAAMABAAEAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.KA = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAwAAAAIAAAACAAAABAAAAAQAgAAMAEAAD8AwAHggGAHQIBgAECAMADAgDAAgIAQAIGAEAEBAAABAwAAAwIAAAYGAAAGBgAAADwAAAAcAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.KI = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAACwAAAAeAAAADgAAAAYAAAATBgAAAz8AAAP5AAxfQAAH8YAAA4GAAAABgHAAAYf4AAD+pAAF8AAMPsAAC/hgAAPAYAABAGAAAABwAAAAYAAAAHAAAAAwAAAAOAAAADAAAAAYAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.KI = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAQAAAAGAAAAAgAAAAIAAAADDAAAAfwAAAeAAAA4gAAAwIAAAABAAAAAZwAAADwAAAHwAAAOGAAAAAgAAAAMAAAADAAAAAQAAAAAAAAAAAAAAAAAAEAAAABgAAAAPmAAAAfwAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.KU = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAQAAAAHAAAAA4AAAAMAAAAHBwAAB/+AAA0XAAAaBkAAGA4AADAOAABgHAAAwBwAAYA4AAMAMAAGAHAAAADgAAABwAAAA0AAAAaAAAAOAAAAHAAAADIAAADgAAACgAAABgAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.KU = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAQAAAAMAAAADAAAABgAAAAQAAAAIAAAAGAAAABAAAAAgAAAAQAAAAEAAAACAAAAAQAAAAEAAAAAgAAAAEAAAABgAAAAIAAAADAAAAAYAAAAGAAAAAwAAAAMAAAABgAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.KE = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAABwAAAAOAAAADgAAABwAAAAYAQAAGAAgABgF8AA79/gAb7gAAGQcQADAHgABgBgAAYAwAAZAMAAMAHAADABgAAgAwAAAAMAAAAGAAAALAAAABwAAAAYAAAAYAAAAMgAAAGAAAACAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.KE = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAABAAAAAYAAIAGAAGABgABgAYAAYAGAAEAB+ABAB/gAQHmAAEABgADAAYAAgAGAAIABgACAAYAAgAGAAIABAACAAQAAgAEAAKABAADgAwAAYAIAAGACAAAgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.KO = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAwCtwAH//8AA+oGAAEABgAAAAYAAAAGAAAABgAAAAQAAAAsAAAADAAIAFwADv//AAf1CQACAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.KO = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/8AAAADwAAAB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAYAAAAD8EAAAH/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.MA = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAFcAIG/3ga/0h4H6gA4AcAAcACAAOAAAAHAAAYDAAAFjgAAAPgAAAB4AAAAOAAAABwAAAAMAAAADAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.MA = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABBAAAAf8AAD+AAAOBAAAAAQAAAAGAAAABgAAAAZwAAAHwAAB/gAAAAYAAAAGAAAABgAAAAYAAAAGAAAARgAAAR4AAAIHgAACDPAAARg4AABAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.MI = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAegAAAC+gAAAB8AAAAHgAAAAYAAAAQAAAAgAAAegAAAB+AAAAD4AAAAPAAAABwAAAAMAAAAAAAAAAAAAAAAAAAUAAAAF8AAAAHwAAAAPgAAAA8AAAAHwAAAAeAAAADAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.MI = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgAAA+YAAAEMAAAADAAAABgAAAAQAAAAMAAAACAAAABgAAAAQAAAAIAIAAGAGAADgBgAO/wQAEIH8ACEAH4AiABnAJgAQQBgAIAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.MU = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAACgAAAAcAAAADgAAAA4AAAAcAAAAHAAAABkAAAAYAAAAMQAAADEAAABwwAAAYGAAAGAwAADAHAAAwA4AAIAOAAWBfwBBX9OAf/oDgH+gAYA6AAGAAEAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.MU = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAYAAAACAAAAAgAwAAIAGAACIAwAA/gEAB+ABAB2AAAAAgAAAAYAAAAGAAAABgAAAAYAAAAGAEAABgBAAGQAQAA0AEAAFABAAAwAQAAEAMAARgCAAGWHgAA8fgAAGAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.ME = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAcAAAABgAAAAcAAAAHAAAADgAAAAwAAABcAABgGAAAfDgAAAewAAAB8AAAAPAAAAD8AAABzgAAA44AAAcHAAAGAwAADAAAACgAAABwAAAAoAAAAcAAAAMAAAAMAAAABAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.ME = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABgAAAAYAABAGAAAIBAAACAwAAAgP4AAMeDgABZgMAAYQBgAOMAYAGiACADJgAgAjQAIAQcACAEGABgBBgAQARsAIAHwAEAAQAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.MO = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAABAAUAASXfgAD7EQAAQwAAAAOAAAABAAAAAwAAAAEAUBADd/wNfaRID1EAAAIDAAAAAwAAAAEAAAADAAAAAQAAAAMAAAABiQAAAf+AAABKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.MO = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAACAAAAAgAAAAIAAAACAAAAB+AAAA/wAAB0AAAABAAAAAQAAAAEAAAABAAAAAQAAAAEYAAAf+AAABwAAAAMAAAACAIAAAgCAAAIAgAACAIAAAgCAAAEBAAABgwAAAP4AAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.NA = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAPAAAAA4AAAAOAAAADAAAAAwBAAAMQAAADAaBAT9/wf/vbcD6DAAAQAxAAAAMAAAADAAAAAwAAAAMAAAAGAAAABgAAAAYAAAAMAAAAGAAAABgAAAAwAAAAYAAAAMAAAAEAAAABAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.NA = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAEAAAADAAAAAgAAAAJgAAAH4AAA/gAAAMQAIAAIABAACAAYABgACAAQAAAAMAAAACAIAAAgCAAAAAgAAAAIAAAACAAAAAgAAAPIAAAEOAAABB4AAAQTgAAD4MAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.NI = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgALAANb/8AB/6pAAMAAAAAACAAAAAAAAAAAAAAAAAAAAAAABAAAIAAAJvAKN//4D/1EGAdAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.NI = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAGAAAABgA/AAYBwAAEAAAABAAAAAQAAAAMAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAAEAAAIAgAADAH/gAwAAAAMAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.NU = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAFgAML38AB/9OAAOgHAAAQBgABAA4AAAAMAADoHAAAPRgAAAfYAAAB4gAAAPQAAADeAAABjwAABwcAAI4DgAA4AcAAcADAAcAAQAaAAAAWAAAACAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.NU = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAABAwAAAIMAAACDf4AAg4DAAIYAYACeACAAZAAgAMQAIAFMACACSAAgBDgAIAwwOGAIMEbACHBDgAjYPsAPCABgBggAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.NE = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAGAAAAA4AAAAHAAAAA4AAAAGAAAABgAAAAJYABAv/AAf+nwAD4DoAAQB4AAAA8AAAB8AAAAeAAAAPQAAAHzgAAHMeAAHDB4ADgwOAHgMBwHADAMKgAwAgAAMAAAADAAAAAwAAAAMAAAADAAAAAwAAAAEAAAAAAAAAAAAA=')
};
hiragana.NE = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAgAAAAMAAAADAAAAAwAAAAIAAAADAHgAA8GIAA+CCAAzBAwAAhAMAAIgDAAGQAwABoAMAAsADAASAAwAFgAMAC4ACAAyAugAcgIYAGYCHABGAecABgABgAYAAIAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.NO = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAGAAAABwAAAAeAAAAOAAAADgAAAAwAAAAcAAAANAAAADAAAABwAAAAYAAAAOAAAAHAAAABgAAAAwAAAAYAAAAMAAAAGAAAAGQAAADAAAADgAAAAkAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.NO = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AAAD44AADEBAABBAIABgQBAAwMAYAICACAEBgAgAAQAIAgMACAICAAgCBgAYAwwAGAEIADABmAAgAPAAQADgAYAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.RA = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAEAAQAIAANTvgAD/u0AAOAAAAAACAAAAAAABAACAAgAt4APf/vAB/UDQAIAJwAAAA4AAAAOAAAAHAAAABgAAAA4AAAAcAAAAOAAAAGgAAADQAAABoAAAA4AAAAcAAAAaAAAAMgAAAEIAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.RA = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAQAAAACAAAAAwAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAIAAAACAAAAAgAAAAYAAAAEAAAABAAAAAQAAAAEA+AADBwQAA3gCAAPgAgADAAIAAAAGAAAADAAAABgAAAAwAAAAgAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.RI = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAQBwAAHgOAAAsDgAAGAwAABgMAAAYDAAAGAwAABgMAAAYDAAAGAwAABgMAAAYDAAAGAwAABgMAAAYDAAACAwAAAAYAAAAGAAAADAAAAEwAAAA0AAAAcAAAAOAAAAOAAAAOAAAAGAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.RI = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAABAAAAAYAAAAGAAAABAQAAAQGAAAEAgAABAIAAAwCAAAIAgAACAIAAAoCAAAOAgAADAIAAAQCAAAEAgAAAAYAAAAGAAAABAAAAAQAAAAEAAAACAAAAAgAAAAAAAAAEAAAACAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.RU = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAABAAAAAeAAAADgAAAA4AAAcGAAADhgAAA4YAAAMGABAGDAAwBkYAYAYGAMAMDAOADAYHAAwGDgAYBjgAMgbwADAHyABgD4AAwA4AAYAEAAMAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.RU = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAO4AAA8MAAAAGAAAADAAAAAgAAAAQAAAAIAAAAGAAAABAAAAAgAAAAQAAAAIYMAAE4BgAB4AIAA4ACAAMAAgAAAAYAAAAEAAATCAAAEZAAAB/AAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.RE = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAACgAAAAeAAAADgAAAAwAAAAMAAAADAAAAAwAAYAMAAMADAAGAAwAGAAsADgADABgAAwBwAAMBwAADA4AAAw8AAAM8AAAD8AAAA+AAAAGAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.RE = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAGAAAYDgAAfBIAANgiAAMQwgAAMYIAAHMCAAB2AgAAnAIAAJgCAAEwAgAAcAIAAvACAAewAggHMAIwBDADwAAwAAAAMAAAABAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.RO = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAYABk3/AAP/a4ADQAYAAwAGAAMABgABAAwAAwAMAAMADAABAAwAAQEMAAEASAADEt4AA/++QAGgAAADAAQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.RO = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAF8wAAAwYAAAAMAAAACAAAABAAAAAwAAAAYAAAAEAAAACAAAABAAAAAg/gAARgGAAPgAgAHgAMADgADAAQAAwAAAAYAAAAOAAAAGAAAAGAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.SA = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAFAAAAA4AABAHAAAdBgAABwYAAAYGAAAGBgAABgYABAYGrAYu//4H/aomA4YGAAAGBgAABgYAAAYGAAAGBgAABgwAAAYMAAACGAAAABgAAAAwAAAAYAAAAOAAAAGAAAADgAAABgAAAAgAAAAAAAAAAAAAAAAAAA=')
};
hiragana.SA = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAGAAAABgAAAAIAAAADAAAAAQgAAAG8AAAB4AAAB8AAAPhgAAAAIAAAABAAAAAYAAAADAAAABwAAAAGAAAAAgAAAAAAAAAAAAAAAAAAAAAAAEAAAAAwAAAAH/AAAAHwAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.SI = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAA0AAAAHgAAAAcAAAAjgAAAAYABAAAAAwEAAAYB4AAMAHgAGAA4ADAAWABgAAgAyAAAAYAAAAcAAAAOAAAAOAAAIHAAAUHgAABnwAAAPwAAAB4AAAAIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.SI = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAQAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAIAQAADA4AAAf4AAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.SU = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAEAAGC/gAE/9cAAOgOAAAgHAAAABwAAAA4AAAAcAAAAGAAAAHgAAAB2AAAA44AAAYHAAAcA4AAOAHAALAA4AHAAOAGgABgDAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.SU = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAADAAAAAQAAAAEAAAABAAAAAQAAAAE/gAAf/4AH4QAAHAEAAAABAAAAAQAAAGkAAABFAAAARQAAAEcAAABDAAAAYwAAAB8AAAAGAAAABgAAAAQAAAAMAAAAGAAAABAAAABgAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.SE = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAA4AAAAHgAAAA4AAAAMAAAADABAAAwG4CAN/vAw36DgH+wDgA6MBwACDA4AAAwZAAAMUAAADMAAAAyAAAAMAAAADAAAAAwAAAAMAAAADAGAAA//gAAL94AAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.SE = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAMAAAgCAAAMAgAADAIAAAwCAAAMAgAADAf8AAx+AAAPhgAAPAQAA8wEAAMMBAAADAwAAAwcAAAEGAAABAAAAAQAAAACAAAAA8OAAAB/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.SO = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAQAAAALAAIAA4ADAAeAAcAHAADIBwAAYA4AAHAOAAAwDAAAIBwAAAAYAAAAMgAAAHAAAADAAAABwAAAAYAAAAMAAAAOAAAAHAAAADgAAADgAAADgAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.SO = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAYAAAAzAAAHxgAAAwwAAAAYAAAAEAAAACAAAABAAAAAgAAAAQDwAAIDwAAEGQAACOIAABeEAAAMCAAAAAAAAAAQAAAAEAAAABAAAAAYAAAADAAAAAYAAAADwAAAAMAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.TA = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAOAAAABwAAAAcAAAAGBYAAB/fAAA1DgAAMA4AAGAcAABgHAAA4DAABdwwAAMPcAAGA+AADADkABgB8AAQAzAAAAMAAAAGAAAADAAAADgAAABwAAAA4AAAAYAAAAcAAAAMAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.TA = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAACAAAABgAAAAYAAAAEAAAADHgAAA/gAAH8AAAAmAAAABAAAAAQAAAAMAAAACAfgABg4AAAQAAAAEAAAADAAAAAgAAAAYAAAAEAAAADAAAAAwDjgAIAP8ACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.TI = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAOAAAAH4AAAPwAAAvgAADe4AAL4OAABADAAABAwAQAAMV4ECv//B7/0IwPQmAAAgDAAAAQwAAAAMAAAADAAAABgAAAAYAAAAMAAAAGAAAACgAAAAwAAAAwAAAAsAAAAMAAAACAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.TI = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAABAAAAAIAAAAGAAAABgAAAAQAAAAEAAAABHAAAB/AAAH4AAAACAAAAAgAAAAQAAAAEAAAABAAAAAQAAAAIPcAACMBgAAsAIAAcACAAGAAgAAAAIAAAAGAAAADAAAABgAAABgAAABgAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.TU = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAACAAAAAyBgAgHAOAGA4DwAwOA8AGBgcABwYHAAcADgADAA4AAQAcAAAAGAAAALgAAABwAAAAYAAAAMAAAAOAAAADAAAADgAAABwAAABwAAABwAAADRAAAAgAAAAAAAAACAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.TU = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/HAAB4AYADwACAPwAAwBgAAMAAAADAAAAAgAAAAYAAAAEAAAADAAAADAAAADgAAADAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.TE = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAACAACAn4AC3/vAAHoAAACQAAAAAAIAAAIAAAgAFfQG3+/8B/YwBAGAOAAAADgAAABgAAAAcAAAAGAAAADAAAABQAAAAYAAAAOAAAADAAAABgAAAAwAAAAwAAAAYAAAAKAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.TE = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAPAAAAbgAAA5gAABwgAADwYAAHgEAAAgCAAAABAAAAAQAAAAAAAAACAAAAAgAAAAIAAAACAAAAAQAAAAEAAAAAgAAAAOAAAABwAAAAHAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.TO = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAA4AAAAHgAAAA4AAAAMAAAADAAAAAwAAAAMAAAADAAAAAwAAAAMAAAAD6AAAAzwAAAMPAAADA4AAAwHAAAMAwAADAEAAAwAAAAMAAAADAAAAAwAAAAMAAAAGAAAABwAAAAMAAAAAAAAAAAAAAAIAAAAAAAA=')
};
hiragana.TO = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAGAAAAAgAAAAMAYAABAHAAAQHAAAGDAAAAhgAAAIwAAABwAAAAYAAAAMAAAAEAAAACAAAABAAAAAQAAAAAAAAACAAAAAAAAAAGAAAAAf/wAAAfgAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.WA = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAACAAANACsAB7//gAPtI4AJgAOAAYADAAMABwABgAYACYAGAAOABgABgA4AAwAcAAGAHAABADgAAAAwAAAAcAAAAOAAAAHAAAADgAAADgAAADgAAAFwAAACgAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.WA = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAgAAAAMAAAADAAAAAwAAAAMAAAADAAAAA8AAAAfAAAAfgAAAIwAAAAIDnAAGCAYACiACAArAAwATAAMAJgADAD4AAgByAAYARgAEAAYACAAGACAABgAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.WI = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAQAAAAPAAAAA4AAAAMAAAADAAAAAwAAAAsEABhLvgAP//cAB5MAAAGDAAADAwAAAQMAAAMDAAADAwcBg19/wf/7UsD1AwAAIAMAAAADAAAAAwAAAAMAAAADAAAAAwAAAAMAAAADAAAAAQAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.WI = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAbAAAB4wAAAMIAAAACAAAABgAAAAQAAAAEAAAADAAAAA3+AAAeAwAAeAGAAZAAgAMQAMAEMADACCAAwBBgAMAwQACAIMDxgBCBGwARAQYADgCcAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.WE = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAFBK4AB//+AAPUHgABADgAAARwAAAOwAAABwAAAAMAAAADAAAAAwAAAAMAAAALAAAgAyVgPv//+B/qIrgIAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.WE = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAA8AAAB3AAAHhgAAAAwAAAAYAAAAMAAAAGAAAADAAAABhwAAAzDAAAaAYAAOAGAADADAAACRgAAANgAAAGAAAADAAAABgAAAAgAAAAwAcAAYAxwAfggGAOGwAwDA4AAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.WO = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAABAAAgAAwAO37/AB//bwAMgAwAAABYAAgAHAAAABgAGFb4AA//uAAHQDAAAAQwAAAAYAAAAOAAAADAAAABgAAAAwAAAAsAAAAGAAAADAAAABgAAABoAAAAwAAAA4AAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.WO = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAMAAAACOAAAB/AAAPwAAAAMAAAACAAAABAAAAAwAgAAIAcAAHMMAADBOAAAAeAAAAGAAAADgAAADIAAABCAAAAgAAAAIAAAACAAAAAgAAAAGBwAAAP8AAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.YA = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAEAAAAD4AAAAOAAAADAAAAAwAIAAGADAABgX4AAa/fAAX6OAZfwHAD9MDgAcDBgAEAwwAAAmYAAABogAAAYAAAAGAAAABgAAAAcAAAADAAAAAwAAAAOAAAADgAAAA4AAAAGAAAABgAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.YA = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAgAAAAGAAAAAgAAAAMAAAQAAAAEAAAABAHGAAQOAwAGcAEAA4ADAA4AAwA7AAYA4QA4AAEAAAAAgAAAAIAAAADAAAAAQAAAAGAAAAAgAAAAMAAAADAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.YU = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAABAC4AAd//AAH2hoAAQAyAAAAMAAAALAAAAAwAAAAMAAAADAAABAwQEABe+Bt//9wP+kAIBwAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.YU = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAgAAAAIAACADAAAwD3AAIDIIACBCDAAgggQAIwIGACICBgBkAgYASAIEAEACBABQBgwAcB4YAGAGcABgB8AAYAQAACAIAAAACAAAABAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAA=')
};
katakana.YO = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAIAlgAD//8AAfUGAACABgAAAAYAAAAMAABABgABBLwAAf/8AAF0DAAAgAwAAAAMAAAADAAAQAwAAgAMAANN3AAD/3wAANAIAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.YO = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAEAAAABgAAAAMAAAACAAAAAgAAAAIAAAACDAAAA3wAAAOAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAPCAAAEPgAABA8AAAQHwAAADPAAA/g8AAAADgAAAAYAAAAAAAAAAAAAAAAA=')
};
katakana.N = {
width: 32,
height: 32,
bpp: 1,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAEAAAABgAAAAOAAAABwAAIAMgAGADgADAAwABgAAAAwAAAAwAAABYAAABOAAAAHAAAAHAAAADgAAADkAAABwAACB4AAAx4AAAP4QAAB8AAAAOAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
hiragana.N = {
width: 32,
height: 32,
bpp: 1,
transparent: 0,
buffer: atob('AAAAAAAAAAAAAAAAAAAAAAAAgAAAAIAAAACAAAABgAAAAQAAAAMAAAACAAAABAAAAAQAAAAIAAAAGAAAABAAAAAkAAAALgAAAFIAIADiAAAAwwBAAYMAQAEBAIADAQGAAgGDAAYAzgAEAHgAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')
};
/// ///////////////////////////////////////// /// /////////////////////////////////////////
let kana = katakana.KI; let kana = katakana.KA;
let scroll = 0; let scroll = 0;
function drawWheel () {
if (scroll > 20 || scroll < -20) {
scroll = 0;
next();
}
}
let hiramode = false; let hiramode = false;
let curkana = 'KA'; let curkana = 'KA';
function next () { function next () {
@ -658,6 +124,7 @@ function next () {
} }
curkana = 'KA'; curkana = 'KA';
kana = hiramode ? hiragana[curkana] : katakana[curkana]; kana = hiramode ? hiragana[curkana] : katakana[curkana];
updateWatch(ohhmm);
} }
function prev () { function prev () {
@ -669,7 +136,6 @@ function prev () {
curkana = oldk; curkana = oldk;
kana = katakana[curkana]; kana = katakana[curkana];
return; return;
} else {
} }
} }
oldk = k; oldk = k;
@ -677,37 +143,18 @@ function prev () {
} }
curkana = oldk; curkana = oldk;
kana = katakana[curkana]; kana = katakana[curkana];
updateWatch(ohhmm);
} }
const kanacolors = { const kanacolors = {
A: [] A: []
}; };
const clocktop = false;
function updateWatch (hhmm) { function updateWatch (hhmm) {
if (!hhmm) { g.setFontAlign(-1, -1, 0);
hhmm = ohhmm;
}
g.setBgColor(0, 0, 0); g.setBgColor(0, 0, 0);
g.setColor(0, 0, 0); g.setColor(0, 0, 0);
if (false) {
g.fillRect(0, 0, g.getWidth(), g.getHeight());
g.setColor(0.3, 0.3, 0.3);
g.setColor(1, 0, 0);
g.fillRect(stripe_pos, 0, stripe_pos + stripe_width, h);
g.fillRect(stripe2_pos, 0, stripe2_pos + stripe_width, h);
for (i = 0; i < h; i += 8) {
g.setColor(0.15, 0.15, 0.15);
g.fillRect(0, i, g.getWidth(), i + 3);
g.setColor(0.4, 0.4, 0.4);
g.fillRect(stripe_pos, i, stripe_pos + stripe_width, i + 3);
g.fillRect(stripe2_pos, i, stripe2_pos + stripe_width, i + 3);
}
} else {
var whitecolor = false; var whitecolor = false;
if (curkana.indexOf('A') != -1) { if (curkana.indexOf('A') != -1) {
g.setColor(1, 0, 0); g.setColor(1, 0, 0);
@ -723,27 +170,15 @@ function updateWatch (hhmm) {
g.setColor(0, 1, 1); g.setColor(0, 1, 1);
} }
g.fillRect(0, 0, w, h); g.fillRect(0, 0, w, h);
}
// GOOD FONT SIZE g.setFont("Vector", 62); g.setFont('Vector', 50);
g.setFont('Vector', 50);
const bignumbers = false;
if (bignumbers) {
g.setColor(1, 1, 1);
g.drawString(hhmm, 12, 12);
g.setColor(0, 0, 0);
g.drawString(hhmm, 10, 10);
} else {
if (whitecolor) { if (whitecolor) {
g.setColor(0, 0, 0); g.setColor(0, 0, 0);
} else { } else {
g.setColor(0.5, 0.5, 0.5); g.setColor(0.5, 0.5, 0.5);
} }
if (clocktop) { x = 26;
x = 26; y = 26; y = h - 42;
} else {
x = 26; y = h - 42;
}
g.drawString(hhmm, x - 3, y - 3); g.drawString(hhmm, x - 3, y - 3);
if (whitecolor) { if (whitecolor) {
g.setColor(1, 1, 1); g.setColor(1, 1, 1);
@ -751,63 +186,59 @@ function updateWatch (hhmm) {
g.setColor(0, 0, 0); g.setColor(0, 0, 0);
} }
g.drawString(hhmm, x, y - 1); g.drawString(hhmm, x, y - 1);
}
// drawKana(hira_a, 0, 60); drawKana(4 + (g.getWidth() / 6), 60);
drawKana(hiragana.KA, g.getWidth() / 6, 60); drawMonthDay();
Bangle.drawWidgets(); Bangle.drawWidgets();
} }
function drawKana (img, x, y) {
function drawMonthDay() {
g.setFont('Vector', 20);
g.setColor(1,1,1);
g.setFontAlign(-1, -1, 0);
g.drawString(month, 4, 112);
g.setFontAlign(1, -1, 0);
g.drawString(day, w, 112);
}
function getPhoneme(k) {
switch (k) {
case "TU": return "TSU";
case "TI": return "CHI";
case "SI": return "SHI";
case "HU": return "FU";
}
return k;
}
function drawKana (x, y) {
g.setColor(0, 0, 0); g.setColor(0, 0, 0);
g.fillRect(0, 0, g.getWidth(), 6 * (h / 8) + 1);
// g.fillRect(0,0,g.getWidth(), h); g.setColor(1, 1, 1);
if (clocktop) { g.drawImage(kana, x + 20, 40, { scale: 1.6 });
g.fillRect(0, h / 2.5, g.getWidth(), h); g.setColor(1, 1, 1);
} else { g.setFont('Vector', 24);
g.fillRect(0, 0, g.getWidth(), 6 * (h / 8) + 1); g.drawString(getPhoneme(curkana), 4, 32);
} g.drawString(hiramode ? 'H' : 'K', w - 20, 32);
if (false) {
g.drawImage(hira_a, x, y);
g.setColor(1, 1, 1);
g.setFont('Vector', 30);
g.drawString(curkana, x + 32, y + 4);
} else {
if (clocktop) {
g.setColor(1, 1, 1);
g.drawImage(kana, x + 8, y + 12, { scale: 3.4 });
g.setColor(1, 1, 1);
g.setFont('Vector', 30);
g.drawString(curkana, 0, y + 16);
g.drawString(hiramode ? 'H' : 'K', w - 20, y + 16);
} else {
g.setColor(1, 1, 1);
g.drawImage(kana, x + 8, 26, { scale: 3.4 });
g.setColor(1, 1, 1);
g.setFont('Vector', 30);
g.drawString(curkana, 4, 32);
g.drawString(hiramode ? 'H' : 'K', w - 20, 32);
}
}
} }
var ohhmm = ''; var ohhmm = '';
function tickWatch () { function tickWatch () {
const now = Date(); const now = Date();
month = now.getMonth() + 1;
day = now.getDate();
function zpad (n) { function zpad (n) {
return (n < 10) ? '0' + n : n; return (n < 10) ? '0' + n : n;
} }
const hhmm = zpad(now.getHours()) + ':' + zpad(now.getMinutes()); const hhmm = zpad(now.getHours()) + ':' + zpad(now.getMinutes());
if (hhmm !== ohhmm) { if (hhmm !== ohhmm) {
updateWatch(hhmm); updateWatch(hhmm);
ohhmm = hhmm;
} }
} }
Bangle.on('touch', function (tap, top) { Bangle.on('touch', function (tap, top) {
if (top.y < h / 3) {
// clocktop = !clocktop;
return;
}
if (top.x < w / 4) { if (top.x < w / 4) {
prev(); prev();
} else if (top.x > (w - (w / 4))) { } else if (top.x > (w - (w / 4))) {
@ -816,10 +247,13 @@ Bangle.on('touch', function (tap, top) {
hiramode = !hiramode; hiramode = !hiramode;
} }
kana = hiramode ? hiragana[curkana] : katakana[curkana]; kana = hiramode ? hiragana[curkana] : katakana[curkana];
tickWatch(); updateWatch(ohhmm);
}); });
g.clear(true);
Bangle.loadWidgets(); Bangle.loadWidgets();
tickWatch(); tickWatch();
setInterval(tickWatch, 1000); setInterval(tickWatch, 1000 * 60);
// show launcher when button pressed
Bangle.setUI('clock');

Binary file not shown.

View File

@ -2,7 +2,7 @@
"id": "kanawatch", "id": "kanawatch",
"name": "Kanawatch", "name": "Kanawatch",
"shortName": "Kanawatch", "shortName": "Kanawatch",
"version": "0.01", "version": "0.03",
"type": "clock", "type": "clock",
"description": "Learn Hiragana and Katakana", "description": "Learn Hiragana and Katakana",
"icon": "app.png", "icon": "app.png",
@ -25,7 +25,7 @@
], ],
"screenshots": [ "screenshots": [
{ {
"url": "screenshot.jpg" "url": "screenshot.png"
} }
] ]
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -4,10 +4,10 @@ A clock inspired by Susan Kare's original 1984 Macintosh desktop design.
Ideas for development: Ideas for development:
- [x] fix dark mode either by forcing black on white or doing proper inverse display and text - [x] fix dark mode either by forcing black on white or doing proper inverse display and text
- [] date in text format - [ ] date in text format
- [] tap to load different info in window - [ ] tap to load different info in window
- [] unlock to show seconds, perhaps flip time and date? - [ ] unlock to show seconds, perhaps flip time and date?
- [] incorporate widgets somehow either by leaving space or adding Chicago font widgets of my own in top bar - [ ] incorporate widgets somehow either by leaving space or adding Chicago font widgets of my own in top bar
![](screenshot.png) ![](screenshot.png)

View File

@ -1,2 +1,3 @@
0.01: Initial implementation 0.01: Initial implementation
0.02: Fix app icon 0.02: Fix app icon
0.03: Fix clock animation issue and reduce source size

View File

@ -2,14 +2,18 @@
// TABANCHI -- たばんち // TABANCHI -- たばんち
const scale = 6; const scale = 6;
let tool = -1;
const w = g.getWidth(); const w = g.getWidth();
const h = g.getHeight(); const h = g.getHeight();
const yy = 34;
const y = 40 - scale;
let tool = -1;
let hd = 1; let hd = 1;
let vd = 1; let vd = 1;
let x = 20; let x = 20;
let sx = 0; // screen scroll x position let sx = 0; // screen scroll x position
const y = 40 - scale; let cacaLevel = 0;
let cacaBirth = null;
let angryState = 0;
let animated = true; let animated = true;
let transition = false; let transition = false;
let caca = null; let caca = null;
@ -22,9 +26,38 @@ let oldMode = '';
let gameChoice = 0; let gameChoice = 0;
let gameTries = 0; let gameTries = 0;
let gameWins = 0; let gameWins = 0;
let statusMode = 0;
let lightSelect = 0;
let lightMode = 0; // on is zero
let frame = 0;
const tama = {
age: 0,
weight: 1,
aspect: 6,
discipline: 0,
happy: 3,
sick: false,
hungry: 3,
cacas: 0,
// hidden
sickness: 0,
defenses: 100,
tummy: 100,
awake: 3
};
g.setBgColor(0); g.setBgColor(0);
const sun = {
width: 8,
height: 8,
bpp: 1,
transparent: 1,
buffer: atob('773nW9rnvfc=')
};
const tama06eat0 = { const tama06eat0 = {
width: 16, width: 16,
height: 16, height: 16,
@ -387,7 +420,6 @@ const caca01 = {
buffer: atob('////v/33v7+3+f4v0HwH////') buffer: atob('////v/33v7+3+f4v0HwH////')
}; };
// var img = hs.decompress(atob("sFggP/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+A"));
const tama00 = { const tama00 = {
width: 16, width: 16,
height: 16, height: 16,
@ -574,23 +606,6 @@ g.drawString('Loading...', 10, 10);
egg = egg00; egg = egg00;
n = tama00; n = tama00;
const tama = {
// visible
age: 0,
weight: 1,
aspect: 6,
discipline: 0,
happy: 3,
sick: false,
hungry: 3,
cacas: 0, // move from cacas
// hidden
sickness: 0,
defenses: 100,
tummy: 100,
awake: 3
};
function drawHearts (n) { function drawHearts (n) {
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
const himg = (i < n) ? heart1 : heart0; const himg = (i < n) ? heart1 : heart0;
@ -599,7 +614,6 @@ function drawHearts (n) {
} }
function drawLinebar (n, arrow) { // 0-100 function drawLinebar (n, arrow) { // 0-100
const yy = 34;
g.drawImage(linebar, 0, yy + (scale * 8), { scale: scale }); g.drawImage(linebar, 0, yy + (scale * 8), { scale: scale });
let wop = scale * 2; // (frame++%2)? scale*3:scale*2; let wop = scale * 2; // (frame++%2)? scale*3:scale*2;
@ -631,7 +645,6 @@ function drawLinebar (n, arrow) { // 0-100
} }
function drawStatus () { function drawStatus () {
const yy = 34;
switch (statusMode) { switch (statusMode) {
case 0: case 0:
g.drawImage(face, scale, yy, { scale: scale }); g.drawImage(face, scale, yy, { scale: scale });
@ -774,11 +787,6 @@ function drawScene () {
} }
} }
var statusMode = 0;
var lightSelect = 0;
var lightMode = 0; // on is zero
let frame = 0;
function drawAngry () { function drawAngry () {
const one = angryState % 2; const one = angryState % 2;
g.drawImage(one ? tama06no0 : tama06no1, (scale * 5), 40, { scale: scale }); g.drawImage(one ? tama06no0 : tama06no1, (scale * 5), 40, { scale: scale });
@ -833,14 +841,6 @@ function drawMedicine () { // food eating animation
g.drawImage(tama06no0, (scale * 10), 40, { scale: scale }); g.drawImage(tama06no0, (scale * 10), 40, { scale: scale });
} }
var sun = {
width: 8,
height: 8,
bpp: 1,
transparent: 1,
buffer: atob('773nW9rnvfc=')
};
function drawEating () { // food eating animation function drawEating () { // food eating animation
const one = angryState % 2; const one = angryState % 2;
const snack = [snack0, snack1, snack2]; const snack = [snack0, snack1, snack2];
@ -953,6 +953,7 @@ function nextItem () {
tool++; tool++;
if (tool > 6) tool = 0; if (tool > 6) tool = 0;
} }
function prevItem () { function prevItem () {
tool--; tool--;
if (tool < 0) tool = 7; if (tool < 0) tool = 7;
@ -1099,7 +1100,6 @@ function drawCaca () {
} }
} }
} }
var angryState = 0;
function animateHappy () { function animateHappy () {
if (transition || mode == 'happy') { if (transition || mode == 'happy') {
@ -1208,7 +1208,7 @@ function animateShower () {
} }
function animateToGame () { function animateToGame () {
if (transition || mode == 'game') { if (transition || mode === 'game') {
return; return;
} }
mode = 'game'; mode = 'game';
@ -1298,14 +1298,6 @@ function button (n) {
} }
if (mode == 'game') { if (mode == 'game') {
/*
if (gameTries > 3) {
mode = "";
gameWins = 0;
gameTries = 0;
//tama.tired++;
}
*/
switch (n) { switch (n) {
case 1: case 1:
// pick left // pick left
@ -1345,8 +1337,7 @@ function button (n) {
drawScene(); drawScene();
break; break;
case 'status': case 'status':
if (oldMode == 'clock') { if (oldMode != 'clock') {
} else {
statusMode++; statusMode++;
drawScene(); drawScene();
} }
@ -1363,8 +1354,7 @@ function button (n) {
animateFromClock(); animateFromClock();
break; break;
case 'status': case 'status':
if (oldMode == 'clock') { if (oldMode != 'clock') {
} else {
statusMode++; statusMode++;
drawScene(); drawScene();
} }
@ -1433,7 +1423,6 @@ function drawGame () {
} }
mode = oldMode; mode = oldMode;
oldMode = ''; oldMode = '';
// g.drawImage();
} else { } else {
g.drawImage(one ? tama06no1 : tama06no0, (scale * 7) + sx, 40, { scale: scale }); g.drawImage(one ? tama06no1 : tama06no0, (scale * 7) + sx, 40, { scale: scale });
} }
@ -1467,7 +1456,6 @@ function drawClock () {
const s1 = numbers[ts[1] - '0']; const s1 = numbers[ts[1] - '0'];
const s2 = numbers[ts[3] - '0']; const s2 = numbers[ts[3] - '0'];
const s3 = numbers[ts[4] - '0']; const s3 = numbers[ts[4] - '0'];
const yy = 34;
// hours // hours
if (s0) { if (s0) {
g.drawImage(s0, wsx, yy, { scale: scale }); g.drawImage(s0, wsx, yy, { scale: scale });
@ -1515,17 +1503,11 @@ function drawClock () {
} }
setInterval(function () { setInterval(function () {
// if (animated) {
updateAnimation(); updateAnimation();
drawScene(); drawScene();
// }
}, 1000); }, 1000);
let cacaLevel = 0; function pooMaker() {
let cacaBirth = null;
setInterval(function () {
// poo maker
if (tama.hungry > 0 && !tama.sleep) { if (tama.hungry > 0 && !tama.sleep) {
const a = 0 | (cacaLevel / tama.tummy); const a = 0 | (cacaLevel / tama.tummy);
const b = 0 | ((cacaLevel + tama.hungry) / tama.tummy); const b = 0 | ((cacaLevel + tama.hungry) / tama.tummy);
@ -1545,9 +1527,8 @@ setInterval(function () {
tama.awake--; tama.awake--;
tama.sleep = false; tama.sleep = false;
} }
}, 5000); }
function sickMaker() {
setInterval(function () {
if (tama.sleep) { if (tama.sleep) {
return; return;
} }
@ -1569,8 +1550,10 @@ setInterval(function () {
if (tama.sick > 0) { if (tama.sick > 0) {
callForAttention = true; callForAttention = true;
} }
}, 2000); }
setInterval(pooMaker, 5e3);
setInterval(sickMaker, 2e3);
updateAnimation(); updateAnimation();
Bangle.on('touch', function (r, s) { Bangle.on('touch', function (r, s) {
@ -1600,4 +1583,3 @@ Bangle.on('touch', function (r, s) {
button(2); button(2);
} }
}); });

View File

@ -2,7 +2,7 @@
"id": "tabanchi", "id": "tabanchi",
"name": "Tabanchi", "name": "Tabanchi",
"shortName": "Tabanchi", "shortName": "Tabanchi",
"version": "0.02", "version": "0.03",
"type": "app", "type": "app",
"description": "Tamagotchi WatchApp", "description": "Tamagotchi WatchApp",
"icon": "app.png", "icon": "app.png",

View File

@ -3,3 +3,6 @@
0.03: Fix crash 0.03: Fix crash
0.04: Use Prompt with dismiss and pause 0.04: Use Prompt with dismiss and pause
Improve barometer value median calculation Improve barometer value median calculation
0.05: Fix warning calculation
Show difference of last measurement to pressure average of the the last three hours in the widget
Only use valid pressure values

View File

@ -19,7 +19,9 @@ Get a notification when the pressure reaches defined thresholds.
* Pause delay: Same as Dismiss delay but longer (useful for meetings and such). From 30 to 240 min * Pause delay: Same as Dismiss delay but longer (useful for meetings and such). From 30 to 240 min
## Widget ## Widget
The widget shows two rows: pressure value of last measurement and pressure average of the the last three hours. The widget shows two rows:
1. pressure value of last measurement
2. difference of last measurement to pressure average of the the last three hours
## Creator ## Creator
Marco ([myxor](https://github.com/myxor)) Marco ([myxor](https://github.com/myxor))

View File

@ -2,13 +2,14 @@
"id": "widbaroalarm", "id": "widbaroalarm",
"name": "Barometer Alarm Widget", "name": "Barometer Alarm Widget",
"shortName": "Barometer Alarm", "shortName": "Barometer Alarm",
"version": "0.04", "version": "0.05",
"description": "A widget that can alarm on when the pressure reaches defined thresholds.", "description": "A widget that can alarm on when the pressure reaches defined thresholds.",
"icon": "widget.png", "icon": "widget.png",
"type": "widget", "type": "widget",
"tags": "tool,barometer", "tags": "tool,barometer",
"supports": ["BANGLEJS2"], "supports": ["BANGLEJS2"],
"readme": "README.md", "readme": "README.md",
"screenshots": [{"url":"screenshot.png"}],
"storage": [ "storage": [
{"name":"widbaroalarm.wid.js","url":"widget.js"}, {"name":"widbaroalarm.wid.js","url":"widget.js"},
{"name":"widbaroalarm.settings.js","url":"settings.js"}, {"name":"widbaroalarm.settings.js","url":"settings.js"},

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -1,141 +1,158 @@
(function() { (function() {
let medianPressure; let medianPressure;
let threeHourAvrPressure; let threeHourAvrPressure;
let currentPressures = []; let currentPressures = [];
let stop = false; // semaphore let stop = false; // semaphore
const LOG_FILE = "widbaroalarm.log.json"; const LOG_FILE = "widbaroalarm.log.json";
const SETTINGS_FILE = "widbaroalarm.json"; const SETTINGS_FILE = "widbaroalarm.json";
const storage = require('Storage'); const storage = require('Storage');
let settings; let settings;
function loadSettings() { function loadSettings() {
settings = Object.assign( settings =
storage.readJSON("widbaroalarm.default.json", true) || {}, Object.assign(storage.readJSON("widbaroalarm.default.json", true) || {},
storage.readJSON(SETTINGS_FILE, true) || {} storage.readJSON(SETTINGS_FILE, true) || {});
); }
}
loadSettings(); loadSettings();
function setting(key) { return settings[key]; }
function setting(key) { function saveSetting(key, value) {
return settings[key]; settings[key] = value;
} storage.write(SETTINGS_FILE, settings);
}
function saveSetting(key, value) { const interval = setting("interval");
settings[key] = value;
storage.write(SETTINGS_FILE, settings);
}
const interval = setting("interval"); let history3 =
storage.readJSON(LOG_FILE, true) || []; // history of recent 3 hours
let history3 = storage.readJSON(LOG_FILE, true) || []; // history of recent 3 hours function showAlarm(body, key, type) {
if (body == undefined)
return;
stop = true;
function showAlarm(body, key) { E.showPrompt(body, {
if (body == undefined) return; title : "Pressure " + (type != undefined ? type : "alarm"),
stop = true; buttons : {"Ok" : 1, "Dismiss" : 2, "Pause" : 3}
}).then(function(v) {
E.showPrompt(body, {
title: "Pressure alarm",
buttons: {
"Ok": 1,
"Dismiss": 2,
"Pause": 3
}
}).then(function(v) {
const tsNow = Math.round(Date.now() / 1000); // seconds
if (v == 1) {
saveSetting(key, tsNow);
}
if (v == 2) {
// save timestamp of the future so that we do not warn again for the same event until then
saveSetting(key, tsNow + 60 * setting('dismissDelayMin'));
}
if (v == 3) {
// save timestamp of the future so that we do not warn again for the same event until then
saveSetting(key, tsNow + 60 * setting('pauseDelayMin'));
}
stop = false;
load();
});
if (setting("buzz") &&
!(storage.readJSON('setting.json', 1) || {}).quiet) {
Bangle.buzz();
}
setTimeout(function() {
stop = false;
load();
}, 20000);
}
function doWeNeedToWarn(key) {
const tsNow = Math.round(Date.now() / 1000); // seconds const tsNow = Math.round(Date.now() / 1000); // seconds
return setting(key) == 0 || setting(key) < tsNow;
if (v == 1) {
saveSetting(key, tsNow);
}
if (v == 2) {
// save timestamp of the future so that we do not warn again for the same
// event until then
saveSetting(key, tsNow + 60 * setting('dismissDelayMin'));
}
if (v == 3) {
// save timestamp of the future so that we do not warn again for the same
// event until then
saveSetting(key, tsNow + 60 * setting('pauseDelayMin'));
}
stop = false;
load();
});
if (setting("buzz") && !(storage.readJSON('setting.json', 1) || {}).quiet) {
Bangle.buzz();
} }
function checkForAlarms(pressure) { setTimeout(function() {
if (pressure == undefined || pressure <= 0) return; stop = false;
load();
}, 20000);
}
let alreadyWarned = false; /*
* returns true if an alarm should be triggered
*/
function doWeNeedToAlarm(key) {
const tsNow = Math.round(Date.now() / 1000); // seconds
return setting(key) == undefined || setting(key) == 0 || tsNow > setting(key);
}
const ts = Math.round(Date.now() / 1000); // seconds function isValidPressureValue(pressure) {
const d = { if (pressure == undefined || pressure <= 0)
"ts": ts, return false;
"p": pressure return pressure > 800 && pressure < 1200; // very rough values
}; }
// delete entries older than 3h function handlePressureValue(pressure) {
for (let i = 0; i < history3.length; i++) { if (pressure == undefined || pressure <= 0)
if (history3[i]["ts"] < ts - (3 * 60 * 60)) { return;
history3.shift();
} const ts = Math.round(Date.now() / 1000); // seconds
} const d = {"ts" : ts, "p" : pressure};
// delete oldest entries until we have max 50
while (history3.length > 50) { history3.push(d);
// delete oldest entries until we have max 50
while (history3.length > 50) {
history3.shift();
}
// delete entries older than 3h
for (let i = 0; i < history3.length; i++) {
if (history3[i]["ts"] < ts - (3 * 60 * 60)) {
history3.shift(); history3.shift();
} else {
break;
} }
}
if (setting("lowalarm")) { // write data to storage
// Is below the alarm threshold? storage.writeJSON(LOG_FILE, history3);
if (pressure <= setting("min")) {
if (!doWeNeedToWarn("lastLowWarningTs")) { calculcate3hAveragePressure();
showAlarm("Pressure low: " + Math.round(pressure) + " hPa", "lastLowWarningTs");
alreadyWarned = true; if (setting("lowalarm") || setting("highalarm") || setting("drop3halarm") ||
} setting("raise3halarm")) {
} else { checkForAlarms(pressure, ts);
saveSetting("lastLowWarningTs", 0); }
}
function checkForAlarms(pressure, ts) {
let alreadyWarned = false;
if (setting("lowalarm")) {
// Is below the alarm threshold?
if (pressure <= setting("min")) {
if (!doWeNeedToAlarm("lowWarnTs")) {
showAlarm("Pressure low: " + Math.round(pressure) + " hPa", "lowWarnTs",
"low");
alreadyWarned = true;
} }
} else {
saveSetting("lowWarnTs", 0);
} }
}
if (setting("highalarm")) { if (setting("highalarm")) {
// Is above the alarm threshold? // Is above the alarm threshold?
if (pressure >= setting("max")) { if (pressure >= setting("max")) {
if (doWeNeedToWarn("lastHighWarningTs")) { if (doWeNeedToAlarm("highWarnTs")) {
showAlarm("Pressure high: " + Math.round(pressure) + " hPa", "lastHighWarningTs"); showAlarm("Pressure high: " + Math.round(pressure) + " hPa",
alreadyWarned = true; "highWarnTs", "high");
} alreadyWarned = true;
} else {
saveSetting("lastHighWarningTs", 0);
} }
} else {
saveSetting("highWarnTs", 0);
} }
}
if (history3.length > 0 && !alreadyWarned) { if (history3.length > 0 && !alreadyWarned) {
// 3h change detection // 3h change detection
const drop3halarm = setting("drop3halarm"); const drop3halarm = setting("drop3halarm");
const raise3halarm = setting("raise3halarm"); const raise3halarm = setting("raise3halarm");
if (drop3halarm > 0 || raise3halarm > 0) { if (drop3halarm > 0 || raise3halarm > 0) {
// we need at least 30min of data for reliable detection // we need at least 30 minutes of data for reliable detection
const diffDateAge = Math.abs(history3[0]["ts"] - ts); const diffDateAge = Math.abs(history3[0]["ts"] - ts);
if (diffDateAge < 10 * 60) { // todo change to 1800 if (diffDateAge > 30 * 60) {
return;
}
// Get oldest entry: // Get oldest entry:
const oldestPressure = history3[0]["p"]; const oldestPressure = history3[0]["p"];
if (oldestPressure != undefined && oldestPressure > 0) { if (oldestPressure != undefined && oldestPressure > 0) {
@ -143,126 +160,145 @@
// drop alarm // drop alarm
if (drop3halarm > 0 && oldestPressure > pressure) { if (drop3halarm > 0 && oldestPressure > pressure) {
if (diffPressure > drop3halarm) { if (diffPressure >= drop3halarm) {
if (doWeNeedToWarn("lastDropWarningTs")) { if (doWeNeedToAlarm("dropWarnTs")) {
showAlarm((Math.round(diffPressure * 10) / 10) + " hPa/3h from " + showAlarm((Math.round(diffPressure * 10) / 10) +
Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "lastDropWarningTs"); " hPa/3h from " + Math.round(oldestPressure) +
" to " + Math.round(pressure) + " hPa",
"dropWarnTs", "drop");
} }
} else { } else {
saveSetting("lastDropWarningTs", 0); if (ts > setting("dropWarnTs"))
saveSetting("dropWarnTs", 0);
} }
} else { } else {
saveSetting("lastDropWarningTs", 0); if (ts > setting("dropWarnTs"))
saveSetting("dropWarnTs", 0);
} }
// raise alarm // raise alarm
if (raise3halarm > 0 && oldestPressure < pressure) { if (raise3halarm > 0 && oldestPressure < pressure) {
if (diffPressure > raise3halarm) { if (diffPressure >= raise3halarm) {
if (doWeNeedToWarn("lastRaiseWarningTs")) { if (doWeNeedToAlarm("raiseWarnTs")) {
showAlarm((Math.round(diffPressure * 10) / 10) + " hPa/3h from " + showAlarm((Math.round(diffPressure * 10) / 10) +
Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "lastRaiseWarningTs"); " hPa/3h from " + Math.round(oldestPressure) +
" to " + Math.round(pressure) + " hPa",
"raiseWarnTs", "raise");
} }
} else { } else {
saveSetting("lastRaiseWarningTs", 0); if (ts > setting("raiseWarnTs"))
saveSetting("raiseWarnTs", 0);
} }
} else { } else {
saveSetting("lastRaiseWarningTs", 0); if (ts > setting("raiseWarnTs"))
saveSetting("raiseWarnTs", 0);
} }
} }
} }
} }
history3.push(d);
// write data to storage
storage.writeJSON(LOG_FILE, history3);
// calculate 3h average for widget
if (history3.length > 0) {
let sum = 0;
for (let i = 0; i < history3.length; i++) {
sum += history3[i]["p"];
}
threeHourAvrPressure = sum / history3.length;
} else {
threeHourAvrPressure = undefined;
}
} }
}
function calculcate3hAveragePressure() {
if (history3 != undefined && history3.length > 0) {
let sum = 0;
for (let i = 0; i < history3.length; i++) {
sum += history3[i]["p"];
}
threeHourAvrPressure = sum / history3.length;
} else {
threeHourAvrPressure = undefined;
}
}
/* /*
turn on barometer power turn on barometer power
take multiple measurements take multiple measurements
sort the results sort the results
take the middle one (median) take the middle one (median)
turn off barometer power turn off barometer power
*/ */
function check() { function getPressureValue() {
if (stop) return; if (stop)
const MEDIANLENGTH = 20; return;
Bangle.setBarometerPower(true, "widbaroalarm"); const MEDIANLENGTH = 20;
Bangle.on('pressure', function(e) { Bangle.setBarometerPower(true, "widbaroalarm");
while (currentPressures.length > MEDIANLENGTH) currentPressures.pop(); Bangle.on('pressure', function(e) {
currentPressures.unshift(e.pressure); while (currentPressures.length > MEDIANLENGTH)
currentPressures.pop();
const pressure = e.pressure;
if (isValidPressureValue(pressure)) {
currentPressures.unshift(pressure);
median = currentPressures.slice().sort(); median = currentPressures.slice().sort();
if (median.length > 10) {
var mid = median.length >> 1;
medianPressure = Math.round(E.sum(median.slice(mid - 4, mid + 5)) / 9);
if (medianPressure > 0) {
turnOff();
checkForAlarms(medianPressure);
}
}
});
setTimeout(function() {
turnOff();
}, 10000);
}
function turnOff() {
if (Bangle.isBarometerOn())
Bangle.setBarometerPower(false, "widbaroalarm");
}
function reload() {
check();
}
function draw() {
if (global.WIDGETS != undefined && typeof global.WIDGETS === "object") {
global.WIDGETS["baroalarm"] = {
width: setting("show") ? 24 : 0,
reload: reload,
area: "tr",
draw: draw
};
} }
g.reset();
if (setting("show")) { if (median.length > 10) {
g.setFont("6x8", 1).setFontAlign(1, 0); var mid = median.length >> 1;
if (medianPressure == undefined) { medianPressure = Math.round(E.sum(median.slice(mid - 4, mid + 5)) / 9);
check(); if (medianPressure > 0) {
const x = this.x, turnOff();
y = this.y; draw();
g.drawString("...", x + 24, y + 6); handlePressureValue(medianPressure);
setTimeout(function() { }
g.setFont("6x8", 1).setFontAlign(1, 0); }
g.drawString(Math.round(medianPressure), x + 24, y + 6); });
}, 10000);
} else { setTimeout(function() { turnOff(); }, 30000);
}
function turnOff() {
if (Bangle.isBarometerOn())
Bangle.setBarometerPower(false, "widbaroalarm");
}
function draw() {
if (global.WIDGETS != undefined && typeof global.WIDGETS === "object") {
global.WIDGETS["baroalarm"] = {
width : setting("show") ? 24 : 0,
area : "tr",
draw : draw
};
}
g.reset();
if (this.x == undefined || this.y != 0)
return; // widget not yet there
g.clearRect(this.x, this.y, this.x + this.width - 1, this.y + 23);
if (setting("show")) {
g.setFont("6x8", 1).setFontAlign(1, 0);
if (medianPressure == undefined) {
// trigger a new check
getPressureValue();
// lets load last value from log (if available)
if (history3.length > 0) {
medianPressure = history3[history3.length - 1]["p"];
g.drawString(Math.round(medianPressure), this.x + 24, this.y + 6); g.drawString(Math.round(medianPressure), this.x + 24, this.y + 6);
} else {
g.drawString("...", this.x + 24, this.y + 6);
} }
} else {
g.drawString(Math.round(medianPressure), this.x + 24, this.y + 6);
}
if (threeHourAvrPressure != undefined && threeHourAvrPressure > 0) { if (threeHourAvrPressure == undefined) {
g.drawString(Math.round(threeHourAvrPressure), this.x + 24, this.y + 6 + 10); calculcate3hAveragePressure();
}
if (threeHourAvrPressure != undefined) {
if (medianPressure != undefined) {
const diff = Math.round(medianPressure - threeHourAvrPressure);
g.drawString((diff > 0 ? "+" : "") + diff, this.x + 24,
this.y + 6 + 10);
} }
} }
} }
}
if (interval > 0) { if (interval > 0) {
setInterval(check, interval * 60000); setInterval(getPressureValue, interval * 60000);
} }
draw(); getPressureValue();
})(); })();

View File

@ -1,2 +1,3 @@
0.01: 25/Jun/2022 Added Screenlock widget to depository. 0.01: 25/Jun/2022 Added Screenlock widget to depository.
0.02: 26/Jun/2022 Tidied up graphics. Fixed versioning style... 0.02: 26/Jun/2022 Tidied up graphics. Fixed versioning style...
0.03: 28/Jun/2022 Tidied up code.

View File

@ -1,14 +1,10 @@
// Screenlock Widget // Screenlock Widget
(() => { (() => {
var widX = 0;
var widY = 0;
function draw() { function draw() {
// Draw icon. // Draw icon.
g.reset(); g.reset();
widX = this.x; g.drawImage(atob("GBiDAkkkkiSSSUkkkkkkiSSSSSUkkkkiSSf/ySSUkkkSSf///ySSkkiST/ySf+SQUkiST+SST+SAUkSSfySSSfwACkSSfySSSewACiSSfySSSWwAASSSfySSSGwAASSSfySSQGwAASST///+222AASST///2222AASST//+A222AASST//wAG22AASST/+AAA22AASST/2wAG22AAUST+22A222ACkiT222A222ACkiSG22A22wAUkkQA22222ACkkkiAG222wAUkkkkSAAAAASkkkkkkSQACSkkkg=="),scrlock.x,scrlock.y);
widY = this.y;
g.drawImage(atob("GBiDAkkkkiSSSUkkkkkkiSSSSSUkkkkiSSf/ySSUkkkSSf///ySSkkiST/ySf+SQUkiST+SST+SAUkSSfySSSfwACkSSfySSSewACiSSfySSSWwAASSSfySSSGwAASSSfySSQGwAASST///+222AASST///2222AASST//+A222AASST//wAG22AASST/+AAA22AASST/2wAG22AAUST+22A222ACkiT222A222ACkiSG22A22wAUkkQA22222ACkkkiAG222wAUkkkkSAAAAASkkkkkkSQACSkkkg=="),widX,widY);
} }
// add widget. // add widget.
@ -18,7 +14,7 @@
draw:draw // Draw widget. draw:draw // Draw widget.
}; };
setInterval(()=>WIDGETS.widscrlock.draw(), 60000); var scrlock = WIDGETS.widscrlock;
function restoreTimeout(){ function restoreTimeout(){
// Restore LCDTimeout settings. // Restore LCDTimeout settings.
@ -27,7 +23,7 @@
var options = []; var options = [];
Bangle.on('touch', function(button, xy) { Bangle.on('touch', function(button, xy) {
if(xy.x>=widX && xy.x<=widX+23 && xy.y>=widY && xy.y<=widY+23) { if(xy.x>=scrlock.x && xy.x<=scrlock.x+23 && xy.y>=scrlock.y && xy.y<=scrlock.y+23) {
options = Bangle.getOptions(); // Store current Timeout settings. options = Bangle.getOptions(); // Store current Timeout settings.
Bangle.setLCDTimeout(0.1); // Lock screen. Bangle.setLCDTimeout(0.1); // Lock screen.
setTimeout(restoreTimeout, 1000); setTimeout(restoreTimeout, 1000);