diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..57fedb0da --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +apps/animclk/V29.LBM.js +apps/banglerun/rollup.config.js diff --git a/.gitignore b/.gitignore index b83632eaa..757619ec5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ .htaccess node_modules package-lock.json +.DS_Store +*.js.bak +appdates.csv +.vscode diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..fd6663d2a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "EspruinoAppLoaderCore"] + path = core + url = https://github.com/espruino/EspruinoAppLoaderCore.git diff --git a/CHANGELOG.md b/CHANGELOG.md index 95e973e0f..2b57c91bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,3 +10,19 @@ Changed for individual apps are listed in `apps/appname/ChangeLog` * Add `Favourite` functionality * Version number now clickable even when you're at the latest version (fix #291) * Rewrite 'getInstalledApps' to minimize RAM usage +* Added code to handle Settings +* Added espruinotools.js for pretokenisation +* Included image and compression tools in repo +* Added better upload of large files (incl. compression) +* URL fetch is now async +* Adding '#search' after the URL (when not the name of a 'filter' chip) will set up search for that term +* If `bin/pre-publish.sh` has been run and recent.csv created, add 'Sort By' chip +* New 'espruinotools' which fixes pretokenise issue when ID follows ID (fix #416) +* Improve upload of binary files +* App description can now be markdown +* Fix `marked is not defined` error (and include in repo, just in case) +* Fix error in 'Install Default Apps' if Flash storage is full enough that erasing takes a while +* Fixed animated progress bar on app removal +* Added ability to specify dependencies (used for `notify` at the moment) +* Fixed Promise-based bug in removeApp +* Fixed bin/firmwaremaker and bin/apploader CLI to handle binary file uploads correctly diff --git a/README.md b/README.md index ca874ad2f..22a12bd5b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Bangle.js App Loader (and Apps) * Try the **release version** at [banglejs.com/apps](https://banglejs.com/apps) * Try the **development version** at [github.io](https://espruino.github.io/BangleApps/) -**All software (including apps) in this repository is MIT Licensed - see [LICENSE](LICENSE)** By +**All software (including apps) in this repository is MIT Licensed - see [LICENSE](LICENSE)** By submitting code to this repository you confirm that you are happy with it being MIT licensed, and that it is not licensed in another way that would make this impossible. @@ -194,14 +194,20 @@ and which gives information about the app for the Launcher. "name":"Short Name", // for Bangle.js menu "icon":"*7chname", // for Bangle.js menu "src":"-7chname", // source file - "type":"widget/clock/app", // optional, default "app" - // if this is 'widget' then it's not displayed in the menu + "type":"widget/clock/app/bootloader", // optional, default "app" + // if this is 'widget' then it's not displayed in the menu // if it's 'clock' then it'll be loaded by default at boot time + // if this is 'bootloader' then it's code that is run at boot time, but is not in a menu "version":"1.23", // added by BangleApps loader on upload based on apps.json "files:"file1,file2,file3", // added by BangleApps loader on upload - lists all files // that belong to the app so it can be deleted + "data":"appid.data.json,appid.data?.json;appidStorageFile,appidStorageFile*" + // added by BangleApps loader on upload - lists files that + // the app might write, so they can be deleted on uninstall + // typically these files are not uploaded, but created by the app + // these can include '*' or '?' wildcards } ``` @@ -212,10 +218,11 @@ and which gives information about the app for the Launcher. "name": "Readable name", // readable name "shortName": "Short name", // short name for launcher "icon": "icon.png", // icon in apps/ - "description": "...", // long description + "description": "...", // long description (can contain markdown) "type":"...", // optional(if app) - 'app'/'widget'/'launch'/'bootloader' "tags": "", // comma separated tag list for searching - + "dependencies" : { "notify":"type" } // optional, app 'types' we depend on + // for instance this will use notify/notifyfs is they exist, or will pull in 'notify' "readme": "README.md", // if supplied, a link to a markdown-style text file // that contains more information about this app (usage, etc) // A 'Read more...' link will be added under the app @@ -240,16 +247,24 @@ and which gives information about the app for the Launcher. "evaluate":true // if supplied, data isn't quoted into a String before upload // (eg it's evaluated as JS) }, + ] + "data": [ // list of files the app writes to + {"name":"appid.data.json", // filename used in storage + "storageFile":true // if supplied, file is treated as storageFile + }, + {"wildcard":"appid.data.*" // wildcard of filenames used in storage + }, // this is mutually exclusive with using "name" + ], "sortorder" : 0, // optional - choose where in the list this goes. // this should only really be used to put system // stuff at the top - ] } ``` * name, icon and description present the app in the app loader. * tags is used for grouping apps in the library, separate multiple entries by comma. Known tags are `tool`, `system`, `clock`, `game`, `sound`, `gps`, `widget`, `launcher` or empty. * storage is used to identify the app files and how to handle them +* data is used to clean up files when the app is uninstalled ### `apps.json`: `custom` element @@ -276,7 +291,7 @@ version of what's in `apps.json`: sendCustomizedApp({ id : "7chname", storage:[ - {name:"7chname.app.js", content:app_source_code}, + {name:"7chname.app.js", url:"app.js", content:app_source_code}, {name:"7chname.img", content:'require("heatshrink").decompress(atob("mEwg...4"))', evaluate:true}, ] }); @@ -289,6 +304,10 @@ version of what's in `apps.json`: This'll then be loaded in to the watch. See [apps/qrcode/grcode.html](the QR Code app) for a clean example. +**Note:** we specify a `url` for JS files even though it doesn't have to exist +and will never be loaded. This is so the app loader can tell if it's a JavaScript +file based on the extension, and if so it can minify and pretokenise it. + ### `apps.json`: `interface` element Apps that create data that can be read back can define a `interface` element in `apps.json`, @@ -328,18 +347,21 @@ See [apps/gpsrec/interface.html](the GPS Recorder) for a full example. Apps (or widgets) can add their own settings to the "Settings" menu under "App/widget settings". To do so, the app needs to include a `settings.js` file, containing a single function that handles configuring the app. -When the app settings are opened, this function is called with one +When the app settings are opened, this function is called with one argument, `back`: a callback to return to the settings menu. +Usually it will save any information in `app.json` where `app` is the name +of your app - so you should change the example accordingly. + Example `settings.js` ```js // make sure to enclose the function in parentheses (function(back) { - let settings = require('Storage').readJSON('app.settings.json',1)||{}; + let settings = require('Storage').readJSON('app.json',1)||{}; function save(key, value) { settings[key] = value; - require('Storage').write('app.settings.json',settings); - } + require('Storage').write('app.json',settings); + } const appMenu = { '': {'title': 'App Settings'}, '< Back': back, @@ -351,19 +373,20 @@ Example `settings.js` E.showMenu(appMenu) }) ``` -In this example the app needs to add both `app.settings.js` and -`app.settings.json` to `apps.json`: +In this example the app needs to add `app.settings.js` to `storage` in `apps.json`. +It should also add `app.json` to `data`, to make sure it is cleaned up when the app is uninstalled. ```json { "id": "app", ... "storage": [ ... {"name":"app.settings.js","url":"settings.js"}, - {"name":"app.settings.json","content":"{}"} + ], + "data": [ + {"name":"app.json"} ] }, ``` -That way removing the app also cleans up `app.settings.json`. ## Coding hints diff --git a/apps.json b/apps.json index 6ce0f11d4..726b9d14b 100644 --- a/apps.json +++ b/apps.json @@ -2,7 +2,7 @@ { "id": "boot", "name": "Bootloader", "icon": "bootloader.png", - "version":"0.14", + "version":"0.21", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "tags": "tool,system", "type":"bootloader", @@ -38,10 +38,10 @@ ] }, { "id": "launch", - "name": "Default Launcher", + "name": "Launcher (Default)", "shortName":"Launcher", "icon": "app.png", - "version":"0.02", + "version":"0.04", "description": "This is needed by Bangle.js to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.", "tags": "tool,system,launcher", "type":"launch", @@ -53,7 +53,7 @@ { "id": "about", "name": "About", "icon": "app.png", - "version":"0.04", + "version":"0.06", "description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers", "tags": "tool,system", "allow_emulator":true, @@ -65,20 +65,46 @@ { "id": "locale", "name": "Languages", "icon": "locale.png", - "version":"0.06", + "version":"0.07", "description": "Translations for different countries", "tags": "tool,system,locale,translate", "type": "locale", "custom":"locale.html", + "readme": "README.md", "storage": [ {"name":"locale"} ], "sortorder" : -10 }, + { "id": "notify", + "name": "Notifications (default)", + "shortName":"Notifications", + "icon": "notify.png", + "version":"0.03", + "description": "A handler for displaying notifications that displays them in a bar at the top of the screen", + "tags": "widget", + "type": "notify", + "readme": "README.md", + "storage": [ + {"name":"notify","url":"notify.js"} + ] + }, + { "id": "notifyfs", + "name": "Fullscreen Notifications", + "shortName":"Notifications", + "icon": "notify.png", + "version":"0.05", + "description": "A handler for displaying notifications that displays them fullscreen. This may not fully restore the screen after on some apps. See `Notifications (default)` for more information about the notifications library.", + "tags": "widget", + "type": "notify", + "storage": [ + {"name":"notify","url":"notify.js"} + ] + }, { "id": "welcome", "name": "Welcome", "icon": "app.png", - "version":"0.07", + "version":"0.09", "description": "Appears at first boot and explains how to use Bangle.js", "tags": "start,welcome", "allow_emulator":true, @@ -86,27 +112,33 @@ {"name":"welcome.boot.js","url":"boot.js"}, {"name":"welcome.app.js","url":"app.js"}, {"name":"welcome.settings.js","url":"settings.js"}, - {"name":"welcome.settings.json","url":"settings-default.json","evaluate":true}, {"name":"welcome.img","url":"app-icon.js","evaluate":true} + ], + "data": [ + {"name":"welcome.json"} ] }, { "id": "gbridge", "name": "Gadgetbridge", "icon": "app.png", - "version":"0.10", + "version":"0.17", "description": "The default notification handler for Gadgetbridge notifications from Android", "tags": "tool,system,android,widget", "type":"widget", + "dependencies": { "notify":"type" }, "storage": [ {"name":"gbridge.settings.js","url":"settings.js"}, {"name":"gbridge.img","url":"app-icon.js","evaluate":true}, {"name":"gbridge.wid.js","url":"widget.js"} + ], + "data": [ + {"name":"gbridge.json"} ] }, { "id": "mclock", "name": "Morphing Clock", "icon": "clock-morphing.png", - "version":"0.03", + "version":"0.06", "description": "7 segment clock that morphs between minutes and hours", "tags": "clock", "type":"clock", @@ -120,13 +152,13 @@ { "id": "setting", "name": "Settings", "icon": "settings.png", - "version":"0.16", + "version":"0.21", "description": "A menu for setting up Bangle.js", "tags": "tool,system", + "readme": "README.md", "storage": [ {"name":"setting.app.js","url":"settings.js"}, {"name":"setting.boot.js","url":"boot.js"}, - {"name":"setting.json","url":"settings-default.json","evaluate":true}, {"name":"setting.img","url":"settings-icon.js","evaluate":true} ], "sortorder" : -2 @@ -135,16 +167,18 @@ "name": "Default Alarm", "shortName":"Alarms", "icon": "app.png", - "version":"0.06", + "version":"0.10", "description": "Set and respond to alarms", "tags": "tool,alarm,widget", "storage": [ {"name":"alarm.app.js","url":"app.js"}, {"name":"alarm.boot.js","url":"boot.js"}, {"name":"alarm.js","url":"alarm.js"}, - {"name":"alarm.json","content":"[]"}, {"name":"alarm.img","url":"app-icon.js","evaluate":true}, {"name":"alarm.wid.js","url":"widget.js"} + ], + "data": [ + {"name":"alarm.json"} ] }, { "id": "wclock", @@ -160,10 +194,40 @@ {"name":"wclock.img","url":"clock-word-icon.js","evaluate":true} ] }, + { "id": "imgclock", + "name": "Image background clock", + "shortName":"Image Clock", + "icon": "app.png", + "version":"0.07", + "description": "A clock with an image as a background", + "tags": "clock", + "type" : "clock", + "custom": "custom.html", + "storage": [ + {"name":"imgclock.app.js","url":"app.js"}, + {"name":"imgclock.img","url":"app-icon.js","evaluate":true}, + {"name":"imgclock.face.img"}, + {"name":"imgclock.face.json"}, + {"name":"imgclock.face.bg","content":""} + ] + }, + { "id": "impwclock", + "name": "Imprecise Word Clock", + "icon": "clock-impword.png", + "version":"0.02", + "description": "Imprecise word clock for vacations, weekends, and those who never need accurate time.", + "tags": "clock", + "type":"clock", + "allow_emulator":true, + "storage": [ + {"name":"impwclock.app.js","url":"clock-impword.js"}, + {"name":"impwclock.img","url":"clock-impword-icon.js","evaluate":true} + ] + }, { "id": "aclock", "name": "Analog Clock", "icon": "clock-analog.png", - "version": "0.11", + "version": "0.13", "description": "An Analog Clock", "tags": "clock", "type":"clock", @@ -189,7 +253,7 @@ { "id": "trex", "name": "T-Rex", "icon": "trex.png", - "version":"0.01", + "version":"0.02", "description": "T-Rex game in the style of Chrome's offline game", "tags": "game", "allow_emulator":true, @@ -201,7 +265,7 @@ { "id": "astroid", "name": "Asteroids!", "icon": "asteroids.png", - "version":"0.01", + "version":"0.02", "description": "Retro asteroids game", "tags": "game", "allow_emulator":true, @@ -235,7 +299,7 @@ { "id": "compass", "name": "Compass", "icon": "compass.png", - "version":"0.01", + "version":"0.03", "description": "Simple compass that points North", "tags": "tool,outdoors", "storage": [ @@ -246,7 +310,7 @@ { "id": "gpstime", "name": "GPS Time", "icon": "gpstime.png", - "version":"0.03", + "version":"0.04", "description": "Update the Bangle.js's clock based on the time from the GPS receiver", "tags": "tool,gps", "storage": [ @@ -269,7 +333,7 @@ { "id": "speedo", "name": "Speedo", "icon": "speedo.png", - "version":"0.01", + "version":"0.04", "description": "Show the current speed according to the GPS", "tags": "tool,outdoors,gps", "storage": [ @@ -280,29 +344,49 @@ { "id": "gpsrec", "name": "GPS Recorder", "icon": "app.png", - "version":"0.07", + "version":"0.12", "interface": "interface.html", "description": "Application that allows you to record a GPS track. Can run in background", "tags": "tool,outdoors,gps,widget", "storage": [ {"name":"gpsrec.app.js","url":"app.js"}, - {"name":"gpsrec.json","url":"app-settings.json","evaluate":true}, {"name":"gpsrec.img","url":"app-icon.js","evaluate":true}, {"name":"gpsrec.wid.js","url":"widget.js"} + ], + "data": [ + {"name":"gpsrec.json"}, + {"wildcard":".gpsrc?","storageFile": true} + ] + }, + { "id": "gpsnav", + "name": "GPS Navigation", + "icon": "icon.png", + "version":"0.04", + "description": "Displays GPS Course and Speed, + Directions to waypoint and waypoint recording, now with waypoint editor", + "tags": "tool,outdoors,gps", + "readme": "README.md", + "interface":"waypoints.html", + "storage": [ + {"name":"gpsnav.app.js","url":"app.js"}, + {"name":"waypoints.json","url":"waypoints.json","evaluate":false}, + {"name":"gpsnav.img","url":"app-icon.js","evaluate":true} ] }, { "id": "heart", "name": "Heart Rate Recorder", "icon": "app.png", - "version":"0.01", + "version":"0.02", "interface": "interface.html", "description": "Application that allows you to record your heart rate. Can run in background", "tags": "tool,health,widget", "storage": [ {"name":"heart.app.js","url":"app.js"}, - {"name":"heart.json","url":"app-settings.json","evaluate":true}, {"name":"heart.img","url":"app-icon.js","evaluate":true}, {"name":"heart.wid.js","url":"widget.js"} + ], + "data": [ + {"name":"heart.json"}, + {"wildcard":".heart?","storageFile": true} ] }, { "id": "slevel", @@ -319,7 +403,7 @@ { "id": "files", "name": "App Manager", "icon": "files.png", - "version":"0.02", + "version":"0.06", "description": "Show currently installed apps, free space, and allow their deletion from the watch", "tags": "tool,system,files", "storage": [ @@ -327,6 +411,24 @@ {"name":"files.img","url":"files-icon.js","evaluate":true} ] }, + { "id": "weather", + "name": "Weather", + "icon": "icon.png", + "version":"0.03", + "description": "Show Gadgetbridge weather report", + "readme": "readme.md", + "tags": "widget,outdoors", + "storage": [ + {"name":"weather.app.js","url":"app.js"}, + {"name":"weather.wid.js","url":"widget.js"}, + {"name":"weather","url":"lib.js"}, + {"name":"weather.img","url":"icon.js","evaluate":true}, + {"name":"weather.settings.js","url":"settings.js"} + ], + "data": [ + {"name": "weather.json"} + ] + }, { "id": "widbat", "name": "Battery Level Widget", "icon": "widget.png", @@ -342,14 +444,34 @@ "name": "Battery Level Widget (with percentage)", "shortName": "Battery Widget", "icon": "widget.png", - "version":"0.09", + "version":"0.11", "description": "Show the current battery level and charging status in the top right of the clock, with charge percentage", "tags": "widget,battery", "type":"widget", "storage": [ {"name":"widbatpc.wid.js","url":"widget.js"}, - {"name":"widbatpc.settings.js","url":"settings.js"}, - {"name":"widbatpc.settings.json","content": "{}"} + {"name":"widbatpc.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"widbatpc.json"} + ] + }, + { "id": "widbatwarn", + "name": "Battery Warning", + "shortName": "Battery Warning", + "icon": "widget.png", + "readme": "README.md", + "version":"0.01", + "description": "Show a warning when the battery runs low.", + "tags": "tool,battery", + "type":"widget", + "dependencies": { "notify":"type" }, + "storage": [ + {"name":"widbatwarn.wid.js","url":"widget.js"}, + {"name":"widbatwarn.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"widbatwarn.json"} ] }, { "id": "widbt", @@ -411,7 +533,7 @@ { "id": "swatch", "name": "Stopwatch", "icon": "stopwatch.png", - "version":"0.06", + "version":"0.07", "interface": "interface.html", "description": "Simple stopwatch with Lap Time logging to a JSON file", "tags": "health", @@ -426,7 +548,7 @@ "name": "Bluetooth Music Controls", "shortName": "Music Control", "icon": "hid-music.png", - "version":"0.01", + "version":"0.02", "description": "Enable HID in settings, pair with your phone, then use this app to control music from your watch!", "tags": "bluetooth", "storage": [ @@ -438,7 +560,7 @@ "name": "Bluetooth Keyboard", "shortName": "Bluetooth Kbd", "icon": "hid-keyboard.png", - "version":"0.01", + "version":"0.02", "description": "Enable HID in settings, pair with your phone/PC, then use this app to control other apps", "tags": "bluetooth", "storage": [ @@ -450,7 +572,7 @@ "name": "Binary Bluetooth Keyboard", "shortName": "Binary BT Kbd", "icon": "hid-binary-keyboard.png", - "version":"0.01", + "version":"0.02", "description": "Enable HID in settings, pair with your phone/PC, then type messages using the onscreen keyboard by tapping repeatedly on the key you want", "tags": "bluetooth", "storage": [ @@ -479,58 +601,60 @@ }, { "id": "qrcode", "name": "Custom QR Code", - "icon": "qrcode.png", - "version":"0.01", + "icon": "app.png", + "version":"0.02", "description": "Use this to upload a customised QR code to Bangle.js", - "tags": "", - "custom": "qrcode.html", + "tags": "qrcode", + "custom": "custom.html", "storage": [ {"name":"qrcode.app.js"}, - {"name":"qrcode.img"} + {"name":"qrcode.img","url":"app-icon.js","evaluate":true} ] }, { "id": "beer", "name": "Beer Compass", - "icon": "beercompass.png", + "icon": "app.png", "version":"0.01", "description": "Uploads all the pubs in an area onto your watch, so it can always point you at the nearest one", "tags": "", - "custom": "beercompass.html", + "custom": "custom.html", "storage": [ {"name":"beer.app.js"}, - {"name":"beer.img"} + {"name":"beer.img","url":"app-icon.js","evaluate":true} ] }, { "id": "route", "name": "Route Viewer", - "icon": "route.png", + "icon": "app.png", "version":"0.01", "description": "Upload a KML file of a route, and have your watch display a map with how far around it you are", "tags": "", - "custom": "route.html", + "custom": "custom.html", "storage": [ {"name":"route.app.js"}, - {"name":"route.img"} + {"name":"route.img","url":"app-icon.js","evaluate":true} ] }, { "id": "ncstart", "name": "NCEU Startup", "icon": "start.png", - "version":"0.04", + "version":"0.06", "description": "NodeConfEU 2019 'First Start' Sequence", "tags": "start,welcome", "storage": [ {"name":"ncstart.app.js","url":"start.js"}, {"name":"ncstart.boot.js","url":"boot.js"}, {"name":"ncstart.settings.js","url":"settings.js"}, - {"name":"ncstart.settings.json","url":"settings-default.json","evaluate":true}, {"name":"ncstart.img","url":"start-icon.js","evaluate":true}, {"name":"nc-bangle.img","url":"start-bangle.js","evaluate":true}, {"name":"nc-nceu.img","url":"start-nceu.js","evaluate":true}, {"name":"nc-nfr.img","url":"start-nfr.js","evaluate":true}, {"name":"nc-nodew.img","url":"start-nodew.js","evaluate":true}, {"name":"nc-tf.img","url":"start-tf.js","evaluate":true} + ], + "data": [ + {"name":"ncstart.json"} ] }, { "id": "ncfrun", @@ -568,6 +692,19 @@ {"name":"sclock.img","url":"clock-simple-icon.js","evaluate":true} ] }, + { "id": "svclock", + "name": "Simple V-Clock", + "icon": "vclock-simple.png", + "version":"0.01", + "description": "Modification of Simple Clock 0.04 to use Vectorfont", + "tags": "clock", + "type":"clock", + "allow_emulator":true, + "storage": [ + {"name":"svclock.app.js","url":"vclock-simple.js"}, + {"name":"svclock.img","url":"vclock-simple-icon.js","evaluate":true} + ] + }, { "id": "dclock", "name": "Dev Clock", "icon": "clock-dev.png", @@ -723,7 +860,7 @@ { "id": "flappy", "name": "Flappy Bird", "icon": "app.png", - "version":"0.03", + "version":"0.04", "description": "A Flappy Bird game clone", "tags": "game", "allow_emulator":true, @@ -763,7 +900,7 @@ "name": "Large Digit Blob Clock", "shortName" : "Blob Clock", "icon": "clock-blob.png", - "version":"0.03", + "version":"0.04", "description": "A clock with big digits", "tags": "clock", "type":"clock", @@ -776,7 +913,7 @@ { "id": "boldclk", "name": "Bold Clock", "icon": "bold_clock.png", - "version":"0.02", + "version":"0.03", "description": "Simple, readable and practical clock", "tags": "clock", "type":"clock", @@ -812,7 +949,7 @@ { "id": "berlinc", "name": "Berlin Clock", "icon": "berlin-clock.png", - "version":"0.02", + "version":"0.03", "description": "Berlin Clock (see https://en.wikipedia.org/wiki/Mengenlehreuhr)", "tags": "clock", "type":"clock", @@ -853,6 +990,7 @@ "name": "Espruino Flag Raiser", "icon": "app.png", "version":"0.01", + "readme": "README.md", "description": "App to send a command to another Espruino to cause it to raise a flag", "tags": "", "storage": [ @@ -878,8 +1016,8 @@ "name": "Torch", "shortName":"Torch", "icon": "app.png", - "version":"0.01", - "description": "Turns screen white to help you see in the dark. Select from the launcher or press BTN3 four times in quick succession to start when in normal clock mode", + "version":"0.02", + "description": "Turns screen white to help you see in the dark. Select from the launcher or press BTN1,BTN3,BTN1,BTN3 quickly to start when in any app that shows widgets", "tags": "tool,torch", "storage": [ {"name":"torch.app.js","url":"app.js"}, @@ -890,7 +1028,8 @@ { "id": "wohrm", "name": "Workout HRM", "icon": "app.png", - "version":"0.06", + "version":"0.07", + "readme": "README.md", "description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.", "tags": "hrm,workout", "type": "app", @@ -916,8 +1055,8 @@ "name": "Grocery", "icon": "grocery.png", "version":"0.01", - "description": "Simple grocery list - Display a list of product and track if you already put them in your cart.", - "tags": "tool,outdoors", + "description": "Simple grocery (shopping) list - Display a list of product and track if you already put them in your cart.", + "tags": "tool,outdoors,shopping,list", "type": "app", "custom":"grocery.html", "storage": [ @@ -929,11 +1068,11 @@ { "id": "marioclock", "name": "Mario Clock", "icon": "marioclock.png", - "version":"0.12", + "version":"0.14", "description": "Animated retro Mario clock, with Gameboy style 8-bit grey-scale graphics.", "tags": "clock,mario,retro", "type": "clock", - "allow_emulator":true, + "allow_emulator":false, "readme": "README.md", "storage": [ {"name":"marioclock.app.js","url":"marioclock-app.js"}, @@ -944,7 +1083,7 @@ "name": "Commandline-Clock", "shortName":"CLI-Clock", "icon": "app.png", - "version":"0.07", + "version":"0.08", "description": "Simple CLI-Styled Clock", "tags": "clock,cli,command,bash,shell", "type":"clock", @@ -968,7 +1107,7 @@ { "id": "barclock", "name": "Bar Clock", "icon": "clock-bar.png", - "version":"0.04", + "version":"0.05", "description": "A simple digital clock showing seconds as a bar", "tags": "clock", "type":"clock", @@ -1017,7 +1156,7 @@ { "id": "astrocalc", "name": "Astrocalc", "icon": "astrocalc.png", - "version":"0.01", + "version":"0.02", "description": "Calculates interesting information on the sun and moon cycles for the current day based on your location.", "tags": "app,sun,moon,cycles,tool,outdoors", "allow_emulator":true, @@ -1048,14 +1187,18 @@ }, { "id": "toucher", "name": "Touch Launcher", - "shortName":"Menu", + "shortName":"Toucher", "icon": "app.png", "version":"0.06", "description": "Touch enable left to right launcher.", "tags": "tool,system,launcher", "type":"launch", + "data": [ + {"name":"toucher.json"} + ], "storage": [ - {"name":"toucher.app.js","url":"app.js"} + {"name":"toucher.app.js","url":"app.js"}, + {"name":"toucher.settings.js","url":"settings.js"} ], "sortorder" : -10 }, @@ -1100,7 +1243,7 @@ { "id": "minionclk", "name": "Minion clock", "icon": "minionclk.png", - "version": "0.01", + "version": "0.04", "description": "Minion themed clock.", "tags": "clock,minion", "type": "clock", @@ -1114,7 +1257,7 @@ "name": "OpenStreetMap", "shortName":"OpenStMap", "icon": "app.png", - "version":"0.02", + "version":"0.03", "description": "[BETA] Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are", "tags": "outdoors,gps", "custom": "custom.html", @@ -1127,22 +1270,22 @@ "name": "Active Pedometer", "shortName":"Active Pedometer", "icon": "app.png", - "version":"0.02", - "description": "Pedometer that filters out arm movement and displays a step goal progress.", + "version":"0.04", + "description": "Pedometer that filters out arm movement and displays a step goal progress. Steps are saved to a daily file and can be viewed as graph.", "tags": "outdoors,widget", - "type":"widget", "readme": "README.md", "storage": [ {"name":"activepedom.wid.js","url":"widget.js"}, {"name":"activepedom.settings.js","url":"settings.js"}, - {"name":"activepedom.img","url":"app-icon.js","evaluate":true} + {"name":"activepedom.img","url":"app-icon.js","evaluate":true}, + {"name":"activepedom.app.js","url":"app.js"} ] }, { "id": "chronowid", "name": "Chrono Widget", "shortName":"Chrono Widget", "icon": "app.png", - "version":"0.01", + "version":"0.03", "description": "Chronometer (timer) which runs as widget.", "tags": "tools,widget", "readme": "README.md", @@ -1193,7 +1336,7 @@ "name": "Battery Chart", "shortName":"Battery Chart", "icon": "app.png", - "version":"0.08", + "version":"0.10", "readme": "README.md", "description": "A widget and an app for recording and visualizing battery percentage over time.", "tags": "app,widget,battery,time,record,chart,tool", @@ -1221,7 +1364,7 @@ "name": "Numerals Clock", "shortName": "Numerals Clock", "icon": "numerals.png", - "version":"0.03", + "version":"0.08", "description": "A simple big numerals clock", "tags": "numerals,clock", "type":"clock", @@ -1229,8 +1372,10 @@ "storage": [ {"name":"numerals.app.js","url":"numerals.app.js"}, {"name":"numerals.img","url":"numerals-icon.js","evaluate":true}, - {"name":"numerals.settings.js","url":"numerals.settings.js"}, - {"name":"numerals.json","url":"numerals-default.json","evaluate":true} + {"name":"numerals.settings.js","url":"numerals.settings.js"} + ], + "data":[ + {"name":"numerals.json"} ] }, { "id": "bledetect", @@ -1263,8 +1408,8 @@ "name": "Calculator", "shortName":"Calculator", "icon": "calculator.png", - "version":"0.01", - "description": "Basic calculator reminiscent of MacOs's one. Handy for small calculus. Push button1 and 3 to navigate up/down, tap right or left to navigate the sides, push button 2 to select.", + "version":"0.02", + "description": "Basic calculator reminiscent of MacOs's one. Handy for small calculus.", "tags": "app,tool", "storage": [ {"name":"calculator.app.js","url":"app.js"}, @@ -1292,5 +1437,769 @@ "evaluate": true } ] - } + }, + { + "id": "buffgym", + "name": "BuffGym", + "icon": "buffgym.png", + "version":"0.02", + "description": "BuffGym is the famous 5x5 workout program for the BangleJS", + "tags": "tool,outdoors,gym,exercise", + "type": "app", + "interface": "buffgym.html", + "allow_emulator": false, + "readme": "README.md", + "storage": [ + {"name":"buffgym.app.js", "url": "buffgym.app.js"}, + {"name":"buffgym-set.js","url":"buffgym-set.js"}, + {"name":"buffgym-exercise.js","url":"buffgym-exercise.js"}, + {"name":"buffgym-workout.js","url":"buffgym-workout.js"}, + {"name":"buffgym-workout-a.json","url":"buffgym-workout-a.json"}, + {"name":"buffgym-workout-b.json","url":"buffgym-workout-b.json"}, + {"name":"buffgym-workout-index.json","url":"buffgym-workout-index.json"}, + {"name":"buffgym.img","url":"buffgym-icon.js","evaluate":true} + ] + }, + { + "id": "banglerun", + "name": "BangleRun", + "shortName": "BangleRun", + "icon": "banglerun.png", + "version": "0.05", + "description": "An app for running sessions.", + "tags": "run,running,fitness,outdoors", + "allow_emulator": false, + "storage": [ + { + "name": "banglerun.app.js", + "url": "app.js" + }, + { + "name": "banglerun.img", + "url": "app-icon.js", + "evaluate": true + } + ] + }, + { + "id": "metronome", + "name": "Metronome", + "icon": "metronome_icon.png", + "version": "0.06", + "readme": "README.md", + "description": "Makes the watch blinking and vibrating with a given rate", + "tags": "tool", + "allow_emulator": true, + "storage": [ + { + "name": "metronome.app.js", + "url": "metronome.js" + }, + { + "name": "metronome.img", + "url": "metronome-icon.js", + "evaluate": true + }, + {"name":"metronome.settings.js","url":"settings.js"} + ] + }, + { "id": "blackjack", + "name": "Black Jack game", + "shortName":"Black Jack game", + "icon": "blackjack.png", + "version":"0.01", + "description": "Simple implementation of card game Black Jack", + "tags": "game", + "allow_emulator":true, + "storage": [ + {"name":"blackjack.app.js","url":"blackjack.app.js"}, + {"name":"blackjack.img","url":"blackjack-icon.js","evaluate":true} + ] + }, + { "id": "hidcam", + "name": "Camera shutter", + "shortName":"Cam shutter", + "icon": "app.png", + "version":"0.03", + "description": "Enable HID, connect to your phone, start your camera and trigger the shot on your Bangle", + "readme": "README.md", + "tags": "bluetooth,tool", + "storage": [ + {"name":"hidcam.app.js","url":"app.js"}, + {"name":"hidcam.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "rclock", + "name": "Round clock with seconds, minutes and date", + "shortName":"Round Clock", + "icon": "app.png", + "version":"0.03", + "description": "Designed round clock with ticks for minutes and seconds and heart rate indication", + "tags": "clock", + "type": "clock", + "storage": [ + {"name":"rclock.app.js","url":"rclock.app.js"}, + {"name":"rclock.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "hamloc", + "name": "QTH Locator / Maidenhead Locator System", + "shortName": "QTH Locator", + "icon": "app.png", + "version":"0.01", + "description": "Convert your current GPS location to the Maidenhead locator system used by HAM amateur radio operators", + "tags": "tool,outdoors,gps", + "readme": "README.md", + "storage": [ + {"name":"hamloc.app.js","url":"app.js"}, + {"name":"hamloc.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "osmpoi", + "name": "POI Compass", + "icon": "app.png", + "version":"0.03", + "description": "Uploads all the points of interest in an area onto your watch, same as Beer Compass with more p.o.i.", + "tags": "tool,outdoors,gps", + "readme": "README.md", + "custom": "custom.html", + "storage": [ + {"name":"osmpoi.app.js"}, + {"name":"osmpoi.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "pong", + "name": "Pong", + "shortName": "Pong", + "icon": "pong.png", + "version": "0.03", + "description": "A clone of the Atari game Pong", + "tags": "game", + "type": "app", + "allow_emulator": true, + "readme": "README.md", + "storage": [ + {"name":"pong.app.js","url":"app.js"}, + {"name":"pong.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "ballmaze", + "name": "Ball Maze", + "icon": "icon.png", + "version": "0.01", + "description": "Navigate a ball through a maze by tilting your watch.", + "readme": "README.md", + "tags": "game", + "type": "app", + "storage": [ + {"name": "ballmaze.app.js","url":"app.js"}, + {"name": "ballmaze.img","url":"icon.js","evaluate": true} + ], + "data": [ + {"name": "ballmaze.json"} + ] + }, + { "id": "calendar", + "name": "Calendar", + "icon": "calendar.png", + "version": "0.01", + "description": "Simple calendar", + "tags": "calendar", + "readme": "README.md", + "allow_emulator": true, + "storage": [ + { + "name": "calendar.app.js", + "url": "calendar.js" + }, + { + "name": "calendar.img", + "url": "calendar-icon.js", + "evaluate": true + } + ] + }, + { "id": "hidjoystick", + "name": "Bluetooth Joystick", + "shortName": "Joystick", + "icon": "app.png", + "version":"0.01", + "description": "Emulates a 2 axis/5 button Joystick using the accelerometer as stick input and buttons 1-3, touch left as button 4 and touch right as button 5.", + "tags": "bluetooth", + "storage": [ + {"name":"hidjoystick.app.js","url":"app.js"}, + {"name":"hidjoystick.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "largeclock", + "name": "Large Clock", + "icon": "largeclock.png", + "version": "0.06", + "description": "A readable and informational digital watch, with date, seconds and moon phase", + "readme": "README.md", + "tags": "clock", + "type": "clock", + "allow_emulator": true, + "storage": [ + { + "name": "largeclock.app.js", + "url": "largeclock.js" + }, + { + "name": "largeclock.img", + "url": "largeclock-icon.js", + "evaluate": true + }, + { + "name": "largeclock.settings.js", + "url": "settings.js" + } + ], + "data": [ + {"name":"largeclock.json"} + ] + }, + { "id": "smtswch", + "name": "Smart Switch", + "shortName":"Smart Switch", + "icon": "app.png", + "version":"0.01", + "description": "Using EspruinoHub, control your smart devices on and off via Bluetooth Low Energy!", + "tags": "bluetooth,btle,smart,switch", + "type": "app", + "readme": "README.md", + "storage": [ + {"name":"smtswch.app.js","url":"app.js"}, + {"name":"smtswch.img","url":"app-icon.js","evaluate":true}, + {"name":"light-on.img","url":"light-on.js","evaluate":true}, + {"name":"light-off.img","url":"light-off.js","evaluate":true}, + {"name":"switch-on.img","url":"switch-on.js","evaluate":true}, + {"name":"switch-off.img","url":"switch-off.js","evaluate":true} + ] + }, + { "id": "miplant", + "name": "Xiaomi Plant Sensor", + "shortName":"Mi Plant", + "icon": "app.png", + "version":"0.01", + "description": "Reads and displays data from Xiaomi bluetooth plant moisture sensors", + "tags": "xiaomi,mi,plant,ble,bluetooth", + "storage": [ + {"name":"miplant.app.js","url":"app.js"}, + {"name":"miplant.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "simpletimer", + "name": "Timer", + "icon": "app.png", + "version": "0.05", + "description": "Simple timer, useful when playing board games or cooking", + "tags": "timer", + "readme": "README.md", + "allow_emulator": true, + "storage": [ + { + "name": "simpletimer.app.js", + "url": "app.js" + }, + { + "name": ".tfnames", + "url": "gesture-tfnames.js", + "evaluate": true + }, + { + "name": ".tfmodel", + "url": "gesture-tfmodel.js", + "evaluate": true + }, + { + "name": "simpletimer.img", + "url": "app-icon.js", + "evaluate": true + } + ], + "data": [ + { + "name": "simpletimer.json" + } + ] + }, + { + "id": "beebclock", + "name": "Beeb Clock", + "icon": "beebclock.png", + "version":"0.02", + "description": "Clock face that may be coincidentally familiar to BBC viewers", + "tags": "clock", + "type": "clock", + "allow_emulator": true, + "storage": [ + {"name":"beebclock.app.js","url":"beebclock.js"}, + {"name":"beebclock.img","url":"beebclock-icon.js","evaluate":true} + ] + }, + { "id": "findphone", + "name": "Find Phone", + "shortName":"Find Phone", + "icon": "app.png", + "version":"0.01", + "description": "Find your phone via Gadgetbridge. Click any button to let your phone ring. 📳", + "tags": "tool,android", + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"findphone.app.js","url":"app.js"}, + {"name":"findphone.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "getup", + "name": "Get Up", + "shortName":"Get Up", + "icon": "app.png", + "version":"0.01", + "description": "Reminds you to getup every x minutes. Sitting to long is dangerous!", + "tags": "tools,health", + "readme": "README.md", + "allow_emulator":true, + "storage": [ + {"name":"getup.app.js","url":"app.js"}, + {"name":"getup.settings.js","url":"settings.js"}, + {"name":"getup.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "gallifr", + "name": "Time Traveller's Chronometer", + "shortName": "Time Travel Clock", + "icon": "gallifr.png", + "version": "0.01", + "description": "A clock for time travellers. The light pie segment shows the minutes, the black circle, the hour. The dial itself reads 'time' just in case you forget.", + "tags": "clock", + "readme": "README.md", + "type": "clock", + "allow_emulator":true, + "storage": [ + { "name": "gallifr.app.js", "url": "app.js" }, + { "name": "gallifr.img", "url": "app-icon.js", "evaluate": true }, + { "name": "gallifr.settings.js", "url": "settings.js" } + ], + "data": [ + {"name":"gallifr.json"} + ] + }, + { "id": "rndmclk", + "name": "Random Clock Loader", + "icon": "rndmclk.png", + "version":"0.03", + "description": "Load a different clock whenever the LCD is switched on.", + "readme": "README.md", + "tags": "widget,clock", + "type":"widget", + "storage": [ + {"name":"rndmclk.wid.js","url":"widget.js"} + ] + }, + { "id": "dotmatrixclock", + "name": "Dotmatrix Clock", + "icon": "dotmatrixclock.png", + "version":"0.01", + "description": "A clear white-on-blue dotmatrix simulated clock", + "tags": "clock,dotmatrix,retro", + "type": "clock", + "allow_emulator":true, + "readme": "README.md", + "storage": [ + {"name":"dotmatrixclock.app.js","url":"app.js"}, + {"name":"dotmatrixclock.img","url":"dotmatrixclock-icon.js","evaluate":true} + ] + }, + { + "id": "jbm8b", + "name": "Magic 8 Ball", + "shortName": "Magic 8 Ball", + "icon": "app.png", + "description": "A simple fortune telling app", + "tags": "game", + "version": "0.03", + "storage": [ + { "name": "jbm8b.app.js", "url": "app.js" }, + { "name": "jbm8b.img", "url": "app-icon.js", "evaluate": true } + ] + }, + { "id": "BLEcontroller", + "name": "BLE Customisable Controller with Joystick", + "shortName": "BLE Controller", + "icon": "BLEcontroller.png", + "version": "0.01", + "description": "A configurable controller for BLE devices and robots, with a basic four direction joystick. Designed to be easy to customise so you can add your own menus.", + "tags": "tool,bluetooth", + "readme": "README.md", + "allow_emulator":false, + "storage": [ + { "name": "BLEcontroller.app.js", "url": "app.js" }, + { "name": "BLEcontroller.img", "url": "app-icon.js", "evaluate": true } + ] + }, + { "id": "widviz", + "name": "Widget Visibility Widget", + "shortName":"Viz Widget", + "icon": "eye.png", + "version":"0.02", + "description": "Swipe left to hide top bar widgets, swipe right to redisplay.", + "tags": "widget", + "type": "widget", + "storage": [ + {"name":"widviz.wid.js","url":"widget.js"} + ] + }, + { "id": "binclock", + "name": "Binary Clock", + "shortName":"Binary Clock", + "icon": "app.png", + "version":"0.02", + "description": "A binary clock with hours and minutes. BTN1 toggles a digital clock.", + "tags": "clock,binary", + "type": "clock", + "storage": [ + {"name":"binclock.app.js","url":"app.js"}, + {"name":"binclock.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "pizzatimer", + "name": "Pizza Timer", + "shortName":"Pizza Timer", + "icon": "pizza.png", + "version":"0.01", + "description": "A timer app for when you cook Pizza. Some say it can also time other things", + "tags": "timer,tool,pizza", + "readme": "README.md", + "storage": [ + {"name":"pizzatimer.app.js","url":"app.js"}, + {"name":"pizzatimer.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "animclk", + "name": "Animated Clock", + "shortName":"Anim Clock", + "icon": "app.png", + "version":"0.02", + "description": "An animated clock face using Mark Ferrari's amazing 8 bit game art and palette cycling: http://www.markferrari.com/art/8bit-game-art", + "tags": "clock,animated", + "type": "clock", + "storage": [ + {"name":"animclk.app.js","url":"app.js"}, + {"name":"animclk.pixels1","url":"animclk.pixels1"}, + {"name":"animclk.pixels2","url":"animclk.pixels2"}, + {"name":"animclk.pal","url":"animclk.pal"}, + {"name":"animclk.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "analogimgclk", + "name": "Analog Clock (Image background)", + "shortName":"Analog Clock", + "icon": "app.png", + "version":"0.02", + "description": "An analog clock with an image background", + "tags": "clock", + "type": "clock", + "storage": [ + {"name":"analogimgclk.app.js","url":"app.js"}, + {"name":"analogimgclk.bg.img","url":"bg.img"}, + {"name":"analogimgclk.img","url":"app-icon.js","evaluate":true} + ] + }, + { + "id": "verticalface", + "name": "Vertical watch face", + "shortName":"Vertical Face", + "icon": "app.png", + "version":"0.05", + "description": "A simple vertical watch face with the date.", + "tags": "clock", + "type":"clock", + "allow_emulator":true, + "storage": [ + {"name":"verticalface.app.js","url":"app.js"}, + {"name":"verticalface.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "sleepphasealarm", + "name": "SleepPhaseAlarm", + "shortName":"SleepPhaseAlarm", + "icon": "app.png", + "version":"0.01", + "description": "Uses the accelerometer to estimate sleep and wake states with the principle of Estimation of Stationary Sleep-segments (ESS, see https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en). This app will read the next alarm from the alarm application and will wake you up to 30 minutes early at the best guessed time when you are almost already awake.", + "tags": "alarm", + "storage": [ + {"name":"sleepphasealarm.app.js","url":"app.js"}, + {"name":"sleepphasealarm.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "life", + "name": "Game of Life", + "icon": "life.png", + "version":"0.04", + "description": "Conway's Game of Life - 16x16 board", + "tags": "game", + "allow_emulator":true, + "storage": [ + {"name":"life.app.js","url":"life.min.js"}, + {"name":"life.img","url":"life-icon.js","evaluate":true} + ] + }, + { "id": "magnav", + "name": "Navigation Compass", + "icon": "magnav.png", + "version":"0.03", + "description": "Compass with linear display as for GPSNAV. Has Tilt compensation and remembers calibration.", + "readme": "README.md", + "tags": "tool,outdoors", + "storage": [ + {"name":"magnav.app.js","url":"magnav.min.js"}, + {"name":"magnav.img","url":"magnav-icon.js","evaluate":true} + ], + "data":[{"name":"magnav.json"}] + }, + { "id": "gpspoilog", + "name": "GPS POI Logger", + "shortName":"GPS POI Log", + "icon": "app.png", + "version":"0.01", + "description": "A simple app to log points of interest with their GPS coordinates and read them back onto your PC. Based on the https://www.espruino.com/Bangle.js+Storage tutorial", + "tags": "outdoors", + "interface": "interface.html", + "storage": [ + {"name":"gpspoilog.app.js","url":"app.js"}, + {"name":"gpspoilog.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "miclock2", + "name": "Mixed Clock 2", + "icon": "clock-mixed.png", + "version":"0.01", + "description": "White color variant of the Mixed Clock with thicker clock hands for better readability in the bright sunlight, extra space under the clock for widgets and seconds in the digital clock.", + "tags": "clock", + "type":"clock", + "allow_emulator":true, + "storage": [ + {"name":"miclock2.app.js","url":"clock-mixed.js"}, + {"name":"miclock2.img","url":"clock-mixed-icon.js","evaluate":true} + ] + }, + { "id": "1button", + "name": "One-Button-Tracker", + "icon": "widget.png", + "version":"0.01", + "interface": "interface.html", + "description": "A widget that turns BTN1 into a tracker, records time of button press/release.", + "tags": "tool,quantifiedself,widget", + "type": "widget", + "readme": "README.md", + "storage": [ + {"name":"1button.wid.js","url":"widget.js"} + ], + "data": [ + {"name":"one_button_presses.csv","storageFile": true} + ] + }, + { "id": "gpsautotime", + "name": "GPS auto time", + "shortName":"GPS auto time", + "icon": "widget.png", + "version":"0.01", + "description": "A widget that automatically updates the Bangle.js time to the GPS time whenever there is a valid GPS fix.", + "tags": "widget,gps", + "type": "widget", + "storage": [ + {"name":"gpsautotime.wid.js","url":"widget.js"} + ] + }, + { "id": "espruinoctrl", + "name": "Espruino Control", + "shortName":"Espruino Ctrl", + "icon": "app.png", + "version":"0.01", + "description": "Send commands to other Espruino devices via the Bluetooth UART interface. Customisable commands!", + "tags": "", + "readme": "README.md", + "custom": "custom.html", + "storage": [ + {"name":"espruinoctrl.app.js"}, + {"name":"espruinoctrl.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "multiclock", + "name": "Multi Clock", + "icon": "multiclock.png", + "version":"0.06", + "description": "Clock with multiple faces - Big, Analogue, Digital, Text.\n Switch between faces with BT1 & BTN3", + "readme": "README.md", + "tags": "clock", + "type":"clock", + "allow_emulator":false, + "storage": [ + {"name":"multiclock.app.js","url":"clock.min.js"}, + {"name":"big.face.js","url":"big.min.js"}, + {"name":"ana.face.js","url":"ana.min.js"}, + {"name":"digi.face.js","url":"digi.min.js"}, + {"name":"txt.face.js","url":"txt.min.js"}, + {"name":"multiclock.img","url":"multiclock-icon.js","evaluate":true} + ] + }, + { "id": "widancs", + "name": "Apple Notification Widget", + "shortName":"ANCS Widget", + "icon": "widget.png", + "version":"0.06", + "description": "Displays call, message etc notifications from a paired iPhone. Read README before installation as it only works with compatible apps", + "readme": "README.md", + "tags": "widget", + "type": "widget", + "storage": [ + {"name":"widancs.wid.js","url":"ancs.min.js"}, + {"name":"widancs.settings.js","url":"settings.js"} + ] + }, + { "id": "accelrec", + "name": "Acceleration Recorder", + "shortName":"Accel Rec", + "icon": "app.png", + "version":"0.01", + "interface": "interface.html", + "description": "This app puts the Bangle's accelerometer into 100Hz mode and reads 2 seconds worth of data after movement starts. The data can then be exported back to the PC.", + "tags": "", + "readme": "README.md", + "storage": [ + {"name":"accelrec.app.js","url":"app.js"}, + {"name":"accelrec.img","url":"app-icon.js","evaluate":true} + ], + "data": [ + {"wildcard":"accelrec.?.csv" } + ] + }, + { + "id": "cprassist", + "name":"CPR Assist", + "icon":"cprassist-icon.png", + "version": "0.01", + "readme": "README.md", + "description": "Provides assistance while performing a CPR", + "tags": "tool,firstaid", + "allow_emulator": true, + "storage": [ + { + "name": "cprassist.app.js", + "url": "cprassist.js" + }, + { + "name": "cprassist.img", + "url": "cprassist-icon.js", + "evaluate": true + }, + { + "name": "cprassist.settings.js", + "url": "settings.js" + } + ] + }, + { "id": "osgridref", + "name": "Ordnance Survey Grid Reference", + "shortName":"OS Grid ref", + "icon": "app.png", + "version":"0.01", + "description": "Displays the UK Ordnance Survey grid reference of your current GPS location. Useful when in the United Kingdom with an Ordnance Survey map", + "tags": "outdoors,gps", + "storage": [ + {"name":"osgridref.app.js","url":"app.js"}, + {"name":"osgridref.img","url":"app-icon.js","evaluate":true} + ] + }, + { "id": "openseizure", + "name": "OpenSeizureDetector Widget", + "shortName":"Short Name", + "icon": "widget.png", + "version":"0.01", + "description": "[BETA!] A widget to work alongside [OpenSeizureDetector](https://www.openseizuredetector.org.uk/)", + "tags": "widget", + "type": "widget", + "readme": "README.md", + "storage": [ + {"name":"openseizure.wid.js","url":"widget.js"} + ] + }, + {"id": "counter", + "name": "Counter", + "icon": "counter_icon.png", + "version": "0.01", + "description": "Simple counter", + "tags": "tool", + "allow_emulator": true, + "storage": [ + {"name": "counter.app.js", "url": "counter.js"}, + {"name": "counter.img", "url": "counter-icon.js", "evaluate": true} + ] + }, + { "id": "bootgattbat", + "name": "BLE GATT Battery Service", + "shortName":"BLE Battery Service", + "icon": "bluetooth.png", + "version":"0.01", + "description": "Adds the GATT Battery Service to advertise the percentage of battery currently remaining over Bluetooth.\n", + "tags": "battery,ble,bluetooth,gatt", + "type": "bootloader", + "readme": "README.md", + "storage": [ + {"name":"gattbat.boot.js","url":"boot.js"} + ] + }, + { "id": "viewstl", + "name": "STL file viewer", + "shortName":"ViewSTL", + "icon": "icons8-octahedron-48.png", + "version":"0.02", + "description": "This app allows you to view STL 3D models on your watch", + "tags": "tool", + "readme": "README.md", + "storage": [ + {"name":"viewstl.app.js","url":"viewstl.min.js"}, + {"name":"viewstl.img","url":"viewstl-icon.js","evaluate":true}, + {"name":"tetra.stl","url":"tetra.stl"}, + {"name":"cube.stl","url":"cube.stl"}, + {"name":"icosa.stl","url":"icosa.stl"} + ] + }, + { "id": "cscsensor", + "name": "Cycling speed sensor", + "shortName":"CSCSensor", + "icon": "icons8-cycling-48.png", + "version":"0.04", + "description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch", + "tags": "outdoors,exercise,ble,bluetooth", + "readme": "README.md", + "storage": [ + {"name":"cscsensor.app.js","url":"cscsensor.app.js"}, + {"name":"cscsensor.settings.js","url":"settings.js"}, + {"name":"cscsensor.img","url":"cscsensor-icon.js","evaluate":true} + ] + }, + { "id": "worldclock", + "name": "World Clock - 4 time zones", + "shortName":"World Clock", + "icon": "app.png", + "version":"0.02", + "description": "Current time zone plus up to four others", + "tags": "clock", + "type" : "clock", + "custom": "custom.html", + "readme": "README.md", + "storage": [ + {"name":"worldclock.app.js","url":"app.js"}, + {"name":"worldclock.settings.json"}, + {"name":"worldclock.img","url":"worldclock-icon.js","evaluate":true} + ] + } ] diff --git a/apps/.eslintrc.json b/apps/.eslintrc.json new file mode 100644 index 000000000..b8c5408e3 --- /dev/null +++ b/apps/.eslintrc.json @@ -0,0 +1,159 @@ +{ + "env": { + // TODO: "espruino": false + // TODO: "banglejs": false + }, + "extends": "eslint:recommended", + "globals": { + // Methods and Fields at https://banglejs.com/reference + "Array": "readonly", + "ArrayBuffer": "readonly", + "ArrayBufferView": "readonly", + "Bangle": "readonly", + "BluetoothDevice": "readonly", + "BluetoothRemoteGATTCharacteristic": "readonly", + "BluetoothRemoteGATTServer": "readonly", + "BluetoothRemoteGATTService": "readonly", + "Boolean": "readonly", + "console": "readonly", + "DataView": "readonly", + "Date": "readonly", + "E": "readonly", + "Error": "readonly", + "Flash": "readonly", + "Float32Array": "readonly", + "Float64Array": "readonly", + "fs": "readonly", + "Function": "readonly", + "Graphics": "readonly", + "heatshrink": "readonly", + "I2C": "readonly", + "Int16Array": "readonly", + "Int32Array": "readonly", + "Int8Array": "readonly", + "InternalError": "readonly", + "JSON": "readonly", + "Math": "readonly", + "Modules": "readonly", + "NRF": "readonly", + "Number": "readonly", + "Object": "readonly", + "OneWire": "readonly", + "Pin": "readonly", + "process": "readonly", + "Promise": "readonly", + "ReferenceError": "readonly", + "RegExp": "readonly", + "Serial": "readonly", + "SPI": "readonly", + "Storage": "readonly", + "StorageFile": "readonly", + "String": "readonly", + "SyntaxError": "readonly", + "tensorflow": "readonly", + "TFMicroInterpreter": "readonly", + "TypeError": "readonly", + "Uint16Array": "readonly", + "Uint24Array": "readonly", + "Uint32Array": "readonly", + "Uint8Array": "readonly", + "Uint8ClampedArray": "readonly", + "Waveform": "readonly", + // Methods and Fields at https://banglejs.com/reference + "analogRead": "readonly", + "analogWrite": "readonly", + "arguments": "readonly", + "atob": "readonly", + "Bluetooth": "readonly", + "BTN": "readonly", + "BTN1": "readonly", + "BTN2": "readonly", + "BTN3": "readonly", + "BTN4": "readonly", + "BTN5": "readonly", + "btoa": "readonly", + "changeInterval": "readonly", + "clearInterval": "readonly", + "clearTimeout": "readonly", + "clearWatch": "readonly", + "decodeURIComponent": "readonly", + "digitalPulse": "readonly", + "digitalRead": "readonly", + "digitalWrite": "readonly", + "dump": "readonly", + "echo": "readonly", + "edit": "readonly", + "encodeURIComponent": "readonly", + "eval": "readonly", + "getPinMode": "readonly", + "getSerial": "readonly", + "getTime": "readonly", + "global": "readonly", + "HIGH": "readonly", + "I2C1": "readonly", + "Infinity": "readonly", + "isFinite": "readonly", + "isNaN": "readonly", + "LED": "readonly", + "LED1": "readonly", + "LED2": "readonly", + "load": "readonly", + "LoopbackA": "readonly", + "LoopbackB": "readonly", + "LOW": "readonly", + "NaN": "readonly", + "parseFloat": "readonly", + "parseInt": "readonly", + "peek16": "readonly", + "peek32": "readonly", + "peek8": "readonly", + "pinMode": "readonly", + "poke16": "readonly", + "poke32": "readonly", + "poke8": "readonly", + "print": "readonly", + "require": "readonly", + "reset": "readonly", + "save": "readonly", + "Serial1": "readonly", + "setBusyIndicator": "readonly", + "setInterval": "readonly", + "setSleepIndicator": "readonly", + "setTime": "readonly", + "setTimeout": "readonly", + "setWatch": "readonly", + "shiftOut": "readonly", + "SPI1": "readonly", + "Terminal": "readonly", + "trace": "readonly", + "VIBRATE": "readonly", + // Aliases and not defined at https://banglejs.com/reference + "g": "readonly", + "WIDGETS": "readonly" + }, + "parserOptions": { + "ecmaVersion": 11 + }, + "rules": { + "indent": [ + "warn", + 2, + { + "SwitchCase": 1 + } + ], + "no-case-declarations": "off", + "no-constant-condition": "off", + "no-delete-var": "off", + "no-empty": "off", + "no-global-assign": "off", + "no-inner-declarations": "off", + "no-octal": "off", + "no-prototype-builtins": "off", + "no-redeclare": "off", + // TODO: "no-undef": "warn", + "no-undef": "off", + "no-unused-vars": "off", + "no-useless-escape": "off" + } +} diff --git a/apps/1button/ChangeLog b/apps/1button/ChangeLog new file mode 100644 index 000000000..4c21f3ace --- /dev/null +++ b/apps/1button/ChangeLog @@ -0,0 +1 @@ +0.01: New Widget! diff --git a/apps/1button/README.md b/apps/1button/README.md new file mode 100644 index 000000000..13a2724c0 --- /dev/null +++ b/apps/1button/README.md @@ -0,0 +1,31 @@ +# The One Button tracker + +A simple widget that turns the `BTN1` of your Bangle.js into a one-button-tracker that can be used right from the clock face and everywhere else. Record when you're sneezing, yawning, eating, or whatever you think the button should track for you. + +![](one-button.GIF) + +## Usage + +Every time you press & release the `BTN1` from the clockface this widget will record the time you pressed & released. While you press the button the Bangle will briefly vibrate and the green LED in the display will light up while you're keeping the button pressed. + +Once you release `BTN1` both the start & end time of your button press will be saved in 2-column `one_button_presses.csv` CSV file on your _Bangle.js_. The CSV file can [be downloaded from the _My Apps_ tab on the Bangle.js app store](https://banglejs.com/apps/). + +To not interfere with alternative usages of `BTN1` (eg when using it for menu navigation) you need to keep the button pressed for at least 130 milliseconds before it triggers a recording (the vibration & LED will inform you about having triggered it). + +## Features + +- Track whatever events you want with a simple button press on your wrist +- Track multiple things with a single button by using different length of button presses +- Easily export the data to visualize your presses in a tool of your choice + +## Controls + +Only makes use of `BTN1` (the top one) right now. + +## Requests + +[Reach out to Bastian](https://www.github.com/gedankenstuecke) if you have feature requests or notice bugs. + +## Creator + +Made by [Bastian Greshake Tzovaras](https://tzovar.as), inspired by the one-button tracker project by Thomas Blomseth Christiansen and Jakob Eg Larsen. diff --git a/apps/1button/interface.html b/apps/1button/interface.html new file mode 100644 index 000000000..7d03e1394 --- /dev/null +++ b/apps/1button/interface.html @@ -0,0 +1,84 @@ + + + + + +
+ + + + + diff --git a/apps/1button/one-button.GIF b/apps/1button/one-button.GIF new file mode 100644 index 000000000..a6adfdb8a Binary files /dev/null and b/apps/1button/one-button.GIF differ diff --git a/apps/1button/widget.js b/apps/1button/widget.js new file mode 100644 index 000000000..cce099309 --- /dev/null +++ b/apps/1button/widget.js @@ -0,0 +1,36 @@ +(() => { + var press_time = new Date(); + + // set widget text + function draw() { + g.reset(); // reset the graphics context to defaults (color/font/etc) + // add your code + g.fillCircle(this.x+6,this.y+6,4); + g.drawString("1BUTTON", this.x+13, this.y+4); + } + + // listen to button press to get start time + setWatch(function(e) { + console.log("Button pressed"); + digitalWrite(LED2,1); + press_time = new Date(); + Bangle.buzz(); + }, BTN1, { repeat: true, edge: 'rising', debounce: 130 }); + + // listen to button go to get end time & write data + setWatch(function(e) { + console.log("Button let go"); + digitalWrite(LED2,0); + var unpress_time = new Date(); + recFile = require("Storage").open("one_button_presses.csv","a"); + recFile.write([press_time.getTime(),unpress_time.getTime()].join(",")+"\n"); + }, BTN1, { repeat: true, edge: 'falling', debounce: 50 }); + + + // add your widget + WIDGETS["1button"]={ + area:"tl", // tl (top left), tr (top right), bl (bottom left), br (bottom right) + width: 100, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout + draw:draw // called to draw the widget + }; +})() diff --git a/apps/1button/widget.png b/apps/1button/widget.png new file mode 100644 index 000000000..6a827c392 Binary files /dev/null and b/apps/1button/widget.png differ diff --git a/apps/BLEcontroller/BLEcontroller.png b/apps/BLEcontroller/BLEcontroller.png new file mode 100644 index 000000000..3fa8575f3 Binary files /dev/null and b/apps/BLEcontroller/BLEcontroller.png differ diff --git a/apps/BLEcontroller/ChangeLog b/apps/BLEcontroller/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/BLEcontroller/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md new file mode 100644 index 000000000..c02e29543 --- /dev/null +++ b/apps/BLEcontroller/README.md @@ -0,0 +1,50 @@ +# BLE Customisable Controller with Joystick + +A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. + +Amaze your friends by controlling your robot, your house or any other BLE device from your watch! + + + +To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: +* message number (up to the least significant four digits) +* screen name (up to four characters) +* object name (up to four characters) +* value/status (up to four characters) + +The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. + +Gordon Williams' EspruinoHub is an excellent way to transform thse BLE advertisements into MQTT messages for further processing. They can be subscribed to via the following MQTT topic (change the watchaddress, to the MAC address of your Bangle.js) +/ble/advertise/wa:tc:ha:dd:re:ss/espruino/# + +## Usage + +The application can be configured at will by changing the definitions of the screens, events, icons and buttons. + +Most changes are possible via data, rather than code change. + +## Features + +The default package contains three configurations: +* a simple home light and sockets controller UI (app.js) +* a robot controller UI with joystick (app-joy.js) +* a simple static assistant controller (app-ex2.js) + +You can try out the other configurations by deleting app.js and renaming the file you want to try as app.js. + +I have tested out the application to as many as eight screens without problems, but four screens are usually enough for most situations. + +## Controls + +The controls will vary by screen, but I suggest a convention of using BTN3 (the bottom button) for moving backwards up the menu stack. + +I have used the convention of red/green for buttons that are switches and blue buttons that provide single function operation (such as navigating a menu or executing a on-off activity) + +## Requests + +In the first instance, please consult my blog post on this application [here](https://k9-build.blogspot.com/2020/05/controlling-k9-using-bluetooth-ble-from.html) + +## Creator + +Richard Hopkins, FIET CEng +May 2020 diff --git a/apps/BLEcontroller/app-ex2.js b/apps/BLEcontroller/app-ex2.js new file mode 100644 index 000000000..27e629d5d --- /dev/null +++ b/apps/BLEcontroller/app-ex2.js @@ -0,0 +1,450 @@ +/* +========================================================== +Simple event based robot controller that enables robot +to switch into automatic or manual control modes. Behaviours +are controlled via a simple finite state machine. +In automatic mode the +robot will look after itself. In manual mode, the watch +will provide simple forward, back, left and right commands. +The messages will be transmitted to a partner BLE Espruino +using BLE +Written by Richard Hopkins, May 2020 +========================================================== +declare global variables for watch button statuses */ +top_btn = false; +middle_btn = false; +left_btn= false; // the left side of the touch screen +right_btn = false; // the right side of the touch screen +bottom_btn = false; + +msgNum = 0; // message number + +/* +CONFIGURATION AREA - STATE VARIABLES +declare global variables for the toggle button +statuses; if you add an additional toggle button +you should declare it and initiase it here */ + +var status_spk = {value: true}; +var status_face = {value: true}; +var status_iris_light = {value: false}; +var status_iris = {value: false}; +var status_hover = {value: false}; +var status_dome = {value: false}; + +/* trsnsmit message +where +s = first character of state, +o = first three character of object name +v = value of state.object +*/ + +const transmit = (state,object,status) => { + msgNum ++; + msg = { + n: msgNum.toString().slice(-4), + s: state.substr(0,4), + o: object.substr(0,4), + v: status.substr(0,4), + }; + message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; + NRF.setAdvertising({},{ + showName: false, + manufacturer: 0x0590, + manufacturerData: JSON.stringify(message)}); +}; + +/* +CONFIGURATION AREA - ICON DEFINITIONS +Retrieve 30px PNG icons from: +https://icons8.com/icon/set/speak/ios-glyphs +Create icons using: +https://www.espruino.com/Image+Converter +Use compression: true +Transparency: true +Diffusion: flat +Colours: 16bit RGB +Ouput as: Image Object +Add an additional element to the icons array +with a unique name and the data from the Image Object +*/ +const icons = [ + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "spk_on", + data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" + }, + { + name: "spk_off", + data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" + }, + { + name: "facerecog", + data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "happy", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" + }, + { + name: "sad", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" + }, + { + name: "hover", + data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" + }, + { + name: "light", + data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" + }, + { + name: "speak", + data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" + }, + { + name: "dalek", + data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" + } + ]; + +/* finds icon data by name in the icon array and returns an image object*/ +const drawIcon = (name) => { + for (var icon of icons) { + if (icon.name == name) { + image = { + width : 30, height : 30, bpp : 16, + transparent : 1, + buffer: require("heatshrink").decompress(atob(icon.data)) + }; + return image;} + } +}; + +/* +CONFIGURATION AREA - BUTTON DEFINITIONS +for a simple button, just define a primary colour +and an icon name from the icon array and +the text to display beneath the button +for toggle buttons, additionally provide secondary +colours, icon name and text. Also provide a reference +to a global variable for the value of the button. +The global variable should be declared at the start of +the program and it may be adviable to use the 'status_name' +format to ensure it is clear. +*/ + +var happyBtn = { + primary_colour: 0x653E, + primary_text: 'Speak', + primary_icon: 'happy', + }; + +var sadBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'sad', + }; + +var speakBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'speak', + }; + +var faceBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'facerecog', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'facerecog', + value: status_face + }; + +var irisLightBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'light', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'light', + value: status_iris_light + }; + +var irisBtn = { + primary_colour: 0xE9C7, + primary_text: 'Closed', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Open', + secondary_icon : 'awake', + value: status_iris + }; + +var hoverBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'hover', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'hover', + value: status_hover + }; + + var domeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'dalek', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'dalek', + value: status_dome + }; + +/* +CONFIGURATION AREA - SCREEN DEFINITIONS +a screen can have a button (as defined above) +on the left and/or the right of the screen. +in adddition a screen can optionally have +an icon for each of the three buttons on +the left hand side of the screen. These +are defined as btn1, bt2 and bt3. The +values are names from the icon array. +*/ + +const menuScreen = { + left: faceBtn, + right: speakBtn, + btn1: "hover", + btn2: "light", +}; + +const speakScreen = { + left: happyBtn, + right: sadBtn, + btn3: "back" +}; + +const irisScreen = { + left: irisBtn, + right: irisLightBtn, + btn3: "back" +}; + +const lightsScreen = { + left: hoverBtn, + right: domeBtn, + btn3: "back" +}; + +/* base state definition +Each of the screens correspond to a state; +this class provides a constuctor for each +of the states +*/ +class State { + constructor(params) { + this.state = params.state; + this.events = params.events; + this.screen = params.screen; + } +} + +/* +CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS +This area defines how each screen behaves. +Each screen corresponds to a different State of the +state machine. This makes it much easier to isolate +behaviours between screens. +The state value is transmitted whenever a button is pressed +to provide context (so the receiving device, knows which +button was pressed on which screen). +The screens are defined above. +The events section identifies if a particular button has been +pressed and released on the screen and an action can then be taken. +The events function receives a notification from a mySetWatch which +provides an event object that identifies which button and whether +it has been pressed down or released. Actions can then be taken. +The events function will always return a State object. +If the events function returns different State from the current +one, then the state machine will change to that new State and redrsw +the screen appropriately. +To add in additional capabilities for button presses, simply add +an additional 'if' statement. +For toggle buttons, the value of the sppropiate status object is +inversed and the new value transmitted. +*/ + +/* The Home State/Page is where the application beings */ + +const Home = new State({ + state: "DalekMenu", + screen: menuScreen, + events: (event) => { + if ((event.object == "top") && (event.status == "end")) { + return Lights; + } + if ((event.object == "middle") && (event.status == "end")) { + return Iris; + } + if ((event.object == "right") && (event.status == "end")) { + return Speak; + } + if ((event.object == "left") && (event.status == "end")) { + status_face.value = !status_face.value; + transmit(this.state, "face", onOff(status_face.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Speak = new State({ + state: "Speak", + screen: speakScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Iris = new State({ + state: "Iris", + screen: irisScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_iris_light.value = !status_iris_light.value; + transmit(this.state, "light", onOff(status_iris_light.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_iris.value = !status_iris.value; + transmit(this.state, "servo", onOff(status_iris.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Lights = new State({ + state: "Lights", + screen: lightsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_dome.value = !status_dome.value; + transmit(this.state, "dome", onOff(status_dome.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_hover.value = !status_hover.value; + transmit(this.state, "hover", onOff(status_hover.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* translate button status into english */ +const startEnd = status => status ? "start" : "end"; + +/* translate status into english */ +const onOff= status => status ? "on" : "off"; + + +/* create watching functions that will change the global +button status when pressed or released +This is actuslly the hesrt of the program. When a button +is not being pressed, nothing is happening (no loops). +This makes the progrsm more battery efficient. +When a setWatch event is raised, the custom callbacks defined +here will be called. These then fired as events to the current +state/screen of the state mschine. +Some events, will result in the stste of the state machine +chsnging, which is why the screen is redrswn after each +button press. +*/ +const setMyWatch = (params) => { + setWatch(() => { + params.bool=!params.bool; + machine = machine.events({object: params.label, status: startEnd(params.bool)}); + drawScreen(machine.screen); + }, params.btn, {repeat:true, edge:"both"}); +}; + +/* object array used to set up the watching functions +*/ +const buttons = [ + {bool : bottom_btn, label : "bottom",btn : BTN3}, + {bool : middle_btn, label : "middle",btn : BTN2}, + {bool : top_btn, label : "top",btn : BTN1}, + {bool : left_btn, label : "left",btn : BTN4}, + {bool : right_btn, label : "right",btn : BTN5} + ]; + +/* set up watchers for buttons */ +for (var button of buttons) + {setMyWatch(button);} + +/* Draw various kinds of buttons */ +const drawButton = (params,side) => { + g.setFontAlign(0,1); + icon = drawIcon(params.primary_icon); + text = params.primary_text; + g.setColor(params.primary_colour); + const x = (side == "left") ? 0 : 120; + if ((params.toggle) && (params.value.value)) { + g.setColor(params.secondary_colour); + text = params.secondary_text; + icon = drawIcon(params.secondary_icon); + } + g.fillRect(0+x,24,119+x, 239); + g.setColor(0x000); + g.setFont("Vector",15); + g.setFontAlign(0,0.0); + g.drawString(text,60+x,160); + options = {rotate: 0, scale:2}; + g.drawImage(icon,x+60,120,options); +}; + +/* Draw the pages corresponding to the states */ +const drawScreen = (params) => { + drawButton(params.left,'left'); + drawButton(params.right,'right'); + g.setColor(0x000); + if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} + if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} + if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} +}; + +machine = Home; // instantiate the state machine at Home +Bangle.drawWidgets(); // draw active widgets +drawScreen(machine.screen); // draw the screen diff --git a/apps/BLEcontroller/app-icon.js b/apps/BLEcontroller/app-icon.js new file mode 100644 index 000000000..662f43c5c --- /dev/null +++ b/apps/BLEcontroller/app-icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("MDCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAAAAAAAABERIQAAAAAAAAAAAAAAAAAAAAAAAAABERIRpiEQAAAAAAAAAAAAAAAAAAAAAAEREhOiImEqYAAAAAAAAAAAAAAAAAAAABESP///8zOFEQAAAAAAAAAAAAAAAAAAARI//////z8zp6AAAAAAAAAAAAAAAAAAES////////PzOFEAAAAAAAAAAAAAAAABEv////////8/MyGgAAAAAAAAAAAAAAARI//////////z8zIRAAAAAAAAAAAAAAARP/////8/P///M/IRAAAAAAAAAAAAAAES/////zgzM///M/OFEAAAAAAAAAAAAAET////84/zMzP/8z8hEAAAAAAAAAAAAAEf////M///gzP/8/MyEAAAAAAAAAAAABEv///zP/8zjzM/8/M4UQAAAAAAAAAAABEv///zP/M48zj//zPyEQAAAAAAAAAAABE////zP/ODMzj//zPyEQAAAAAAAAAAABE////zMzjyM48//zPyEQAAAAAAAAAAABE/////ODMzOPP/8/M4QQAAAAAAAAAAABE/////MzjzOD///zPyEQAAAAAAAAAAABE/////8zOPMz///zMzEQAAAAAAAAAAABEj//////PzP///8/MxhQAAAAAAAAAAARES////////////8/MRpyAAAAAAAAAAASMRP////////////zMRMhAAAAAAAAAAARMR////////////8/IRMhAAAAAAAAAAARES/////////////zMhp6AAAAAAAAAAEREv////////////8/MyEacAAAAAAAABERIv/////////////zPyERGAAAAAAAABEBE//////////////zPyEQEQAAAAAAAREBE//////////////zPyEQERAAAAABERABE//////////////zPyEQAREQAAEREgABE//////////////zPyEQABERIAESESABE//////////////zPyEQARESEAEfIRABE//////////////zPyEQAREBEAEREgABE//////z//////8/MzEQABERIAAREQABE/8/8z/zPz/z8/M/MzGAABERAAABEQABE/8/8/8/Pz/z8/PzPyEQABEQAAAAEQABE//////////////zPyEQABEAAAAAERAAETMzMzMzMjMzMzODIxEAAREAAAAAARAAEREhGmIRGhESaiYRKmEAARAAAAAAEREgABERIaYhEaERJqEmEQABERIAAAABERIaAAAAAAEREhGmIREAAAARESGgAAABEAARAAAAAAEREhGmIRGgAAARAAEQAAABEAARAAABERIRpiERoREgAAARAAEQAAAAAAAAAAABERIRpiERoREgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")) diff --git a/apps/BLEcontroller/app-joy.js b/apps/BLEcontroller/app-joy.js new file mode 100644 index 000000000..0735aeee6 --- /dev/null +++ b/apps/BLEcontroller/app-joy.js @@ -0,0 +1,446 @@ +/* +========================================================== +Simple event based robot controller that enables robot +to switch into automatic or manual control modes. Behaviours +are controlled via a simple finite state machine. +In automatic mode the +robot will look after itself. In manual mode, the watch +will provide simple forward, back, left and right commands. +The messages will be transmitted to a partner BLE Espruino +using BLE +Written by Richard Hopkins, May 2020 +========================================================== +declare global variables for watch button statuses */ +top_btn = false; +middle_btn = false; +left_btn= false; // the left side of the touch screen +right_btn = false; // the right side of the touch screen +bottom_btn = false; + +msgNum = 0; // message number + +NRF.setConnectionInterval(100); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +/* +CONFIGURATION AREA - STATE VARIABLES +declare global variables for the toggle button +statuses; if you add an additional toggle button +you should declare it and initiase it here */ + +var status_auto = {value: false}; +var status_chess = {value: false}; +var status_wake = {value: false}; + +/* trsnsmit message +where +s = first character of state, +o = first three character of object name +v = value of state.object +*/ + +const transmit = (state,object,status) => { + msgNum ++; + msg = { + n: msgNum.toString().slice(-4), + s: state.substr(0,4), + o: object.substr(0,4), + v: status.substr(0,4), + }; + message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; + NRF.setAdvertising({},{ + showName: false, + manufacturer: 0x0590, + manufacturerData: JSON.stringify(message)}); +}; + +/* +CONFIGURATION AREA - ICON DEFINITIONS +Retrieve 30px PNG icons from: +https://icons8.com/icon/set/speak/ios-glyphs +Create icons using: +https://www.espruino.com/Image+Converter +Use compression: true +Transparency: true +Diffusion: flat +Colours: 16bit RGB +Ouput as: Image Object +Add an additional element to the icons array +with a unique name and the data from the Image Object +*/ +const icons = [ + { + name: "walk", + data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" + }, + { + name: "sit", + data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" + }, + { + name: "joystick", + data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" + }, + { + name: "left", + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + }, + { + name: "right", + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + }, + { + name: "forward", + data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" + }, + { + name: "backward", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" + }, + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "mic_on", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" + }, + { + name: "comms", + data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + }, + { + name: "pawn", + data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "wag_h", + data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" + }, + { + name: "wag_v", + data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" + } + ]; + +/* finds icon data by name in the icon array and returns an image object*/ +const drawIcon = (name) => { + for (var icon of icons) { + if (icon.name == name) { + image = { + width : 30, height : 30, bpp : 16, + transparent : 1, + buffer: require("heatshrink").decompress(atob(icon.data)) + }; + return image;} + } +}; + +/* +CONFIGURATION AREA - BUTTON DEFINITIONS +for a simple button, just define a primary colour +and an icon name from the icon array and +the text to display beneath the button +for toggle buttons, additionally provide secondary +colours, icon name and text. Also provide a reference +to a global variable for the value of the button. +The global variable should be declared at the start of +the program and it may be adviable to use the 'status_name' +format to ensure it is clear. +*/ + +var joystickBtn = { + primary_colour: 0x653E, + primary_icon: 'joystick', + primary_text: 'Joystick', + }; + +var turnLeftBtn = { + primary_colour: 0x653E, + primary_text: 'Left', + primary_icon: 'left', + }; + +var turnRightBtn = { + primary_colour: 0x33F9, + primary_text: 'Right', + primary_icon: 'right', + }; + +var tailHBtn = { + primary_colour: 0x653E, + primary_text: 'Wag Tail', + primary_icon: 'wag_h', + }; + +var tailVBtn = { + primary_colour: 0x33F9, + primary_text: 'Wag Tail', + primary_icon: 'wag_v', + }; + +var chessBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'pawn', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'pawn', + value: status_chess + }; + +var wakeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Sleeping', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Awake', + secondary_icon : 'awake', + value: status_wake + }; + +var autoBtn = { + primary_colour: 0xE9C7, + primary_text: 'Stop', + primary_icon: 'sit', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Move', + secondary_icon : 'walk', + value: status_auto + }; + +/* +CONFIGURATION AREA - SCREEN DEFINITIONS +a screen can have a button (as defined above) +on the left and/or the right of the screen. +in adddition a screen can optionally have +an icon for each of the three buttons on +the left hand side of the screen. These +are defined as btn1, bt2 and bt3. The +values are names from the icon array. +*/ +const menuScreen = { + left: wakeBtn, + right: joystickBtn, + btn1: "pawn", + btn2: "wag_v", +}; + +const joystickScreen = { + left: turnLeftBtn, + right: turnRightBtn, + btn1: "forward", + btn2: "backward", + btn3: "back" +}; + +const tailScreen = { + left: tailHBtn, + right: tailVBtn, + btn3: "back" +}; + +const chessScreen = { + left: chessBtn, + right: autoBtn, + btn3: "back" +}; + + +/* base state definition +Each of the screens correspond to a state; +this class provides a constuctor for each +of the states +*/ +class State { + constructor(params) { + this.state = params.state; + this.events = params.events; + this.screen = params.screen; + } +} + +/* +CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS +This area defines how each screen behaves. +Each screen corresponds to a different State of the +state machine. This makes it much easier to isolate +behaviours between screens. +The state value is transmitted whenever a button is pressed +to provide context (so the receiving device, knows which +button was pressed on which screen). +The screens are defined above. +The events section identifies if a particular button has been +pressed and released on the screen and an action can then be taken. +The events function receives a notification from a mySetWatch which +provides an event object that identifies which button and whether +it has been pressed down or released. Actions can then be taken. +The events function will always return a State object. +If the events function returns different State from the current +one, then the state machine will change to that new State and redrsw +the screen appropriately. +To add in additional capabilities for button presses, simply add +an additional 'if' statement. +For toggle buttons, the value of the appropiate status object is +inversed and the new value transmitted. +*/ + +/* The Home State/Page is where the application beings */ + +const Home = new State({ + state: "K9Menu", + screen: menuScreen, + events: (event) => { + if ((event.object == "top") && (event.status == "end")) { + return Chess; + } + if ((event.object == "middle") && (event.status == "end")) { + return Tail; + } + if ((event.object == "right") && (event.status == "end")) { + return Joystick; + } + if ((event.object == "left") && (event.status == "end")) { + status_wake.value = !status_wake.value; + transmit(this.state, "wake", onOff(status_wake.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Chess = new State({ + state: "Chess", + screen: chessScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_auto.value = !status_auto.value; + transmit(this.state, "follow", onOff(status_auto.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_chess.value = !status_chess.value; + transmit(this.state, "chess", onOff(status_chess.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Tail = new State({ + state: "Tail", + screen: tailScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* Joystick page state */ +const Joystick = new State({ + state: "Joystick", + screen: joystickScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + transmit("Joystick", "joystick", "off"); + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* translate button status into english */ +const startEnd = status => status ? "start" : "end"; + +/* translate status into english */ +const onOff= status => status ? "on" : "off"; + + +/* create watching functions that will change the global +button status when pressed or released +This is actuslly the hesrt of the program. When a button +is not being pressed, nothing is happening (no loops). +This makes the progrsm more battery efficient. +When a setWatch event is raised, the custom callbacks defined +here will be called. These then fired as events to the current +state/screen of the state mschine. +Some events, will result in the stste of the state machine +chsnging, which is why the screen is redrswn after each +button press. +*/ +const setMyWatch = (params) => { + setWatch(() => { + params.bool=!params.bool; + machine = machine.events({object: params.label, status: startEnd(params.bool)}); + drawScreen(machine.screen); + }, params.btn, {repeat:true, edge:"both"}); +}; + +/* object array used to set up the watching functions +*/ +const buttons = [ + {bool : bottom_btn, label : "bottom",btn : BTN3}, + {bool : middle_btn, label : "middle",btn : BTN2}, + {bool : top_btn, label : "top",btn : BTN1}, + {bool : left_btn, label : "left",btn : BTN4}, + {bool : right_btn, label : "right",btn : BTN5} + ]; + +/* set up watchers for buttons */ +for (var button of buttons) + {setMyWatch(button);} + +/* Draw various kinds of buttons */ +const drawButton = (params,side) => { + g.setFontAlign(0,1); + icon = drawIcon(params.primary_icon); + text = params.primary_text; + g.setColor(params.primary_colour); + const x = (side == "left") ? 0 : 120; + if ((params.toggle) && (params.value.value)) { + g.setColor(params.secondary_colour); + text = params.secondary_text; + icon = drawIcon(params.secondary_icon); + } + g.fillRect(0+x,28,119+x, 239); + g.setColor(0x000); + g.setFont("Vector",15); + g.setFontAlign(0,0.0); + g.drawString(text,60+x,160); + options = {rotate: 0, scale:2}; + g.drawImage(icon,x+60,120,options); +}; + +/* Draw the pages corresponding to the states */ +const drawScreen = (params) => { + drawButton(params.left,'left'); + drawButton(params.right,'right'); + g.setColor(0x000); + if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} + if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} + if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} +}; + +machine = Home; // instantiate the state machine at Home +Bangle.drawWidgets(); // draw active widgets +drawScreen(machine.screen); // draw the screen diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js new file mode 100644 index 000000000..c8217988c --- /dev/null +++ b/apps/BLEcontroller/app.js @@ -0,0 +1,368 @@ +/* +========================================================== +Simple event based robot controller that enables robot +to switch into automatic or manual control modes. Behaviours +are controlled via a simple finite state machine. +In automatic mode the +robot will look after itself. In manual mode, the watch +will provide simple forward, back, left and right commands. +The messages will be transmitted to a partner BLE Espruino +using BLE +Written by Richard Hopkins, May 2020 +========================================================== +declare global variables for watch button statuses */ +top_btn = false; +middle_btn = false; +left_btn= false; // the left side of the touch screen +right_btn = false; // the right side of the touch screen +bottom_btn = false; + +msgNum = 0; // message number + +NRF.setConnectionInterval(100); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +/* +CONFIGURATION AREA - STATE VARIABLES +declare global variables for the toggle button +statuses; if you add an additional toggle button +you should declare it and initiase it here */ + +var status_printer = {value: false}; +var status_tv = {value: false}; +var status_light_hall = {value: false}; +var status_light_study = {value: false}; + +/* trsnsmit message +where +s = first character of state, +o = first three character of object name +v = value of state.object +*/ + +const transmit = (state,object,status) => { + msgNum ++; + msg = { + n: msgNum.toString().slice(-4), + s: state.substr(0,4), + o: object.substr(0,4), + v: status.substr(0,4), + }; + message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; + NRF.setAdvertising({},{ + showName: false, + manufacturer: 0x0590, + manufacturerData: JSON.stringify(message)}); +}; + +/* +CONFIGURATION AREA - ICON DEFINITIONS +Retrieve 30px PNG icons from: +https://icons8.com/icon/set/speak/ios-glyphs +Create icons using: +https://www.espruino.com/Image+Converter +Use compression: true +Transparency: true +Diffusion: flat +Colours: 16bit RGB +Ouput as: Image Object +Add an additional element to the icons array +with a unique name and the data from the Image Object +*/ +const icons = [ + { + name: "switch", + data: "gEBAP4B/AP4B/AP4B/AMgA3HPJdlVvI7/Hf47/Hf47/Hf47/Hf47/Hf4AvIPKRXAP4B/AP4B/AP4B/AJgA==" + }, + { + name: "light", + data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" + }, + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + } + ]; + +/* finds icon data by name in the icon array and returns an image object*/ +const drawIcon = (name) => { + for (var icon of icons) { + if (icon.name == name) { + image = { + width : 30, height : 30, bpp : 16, + transparent : 1, + buffer: require("heatshrink").decompress(atob(icon.data)) + }; + return image;} + } +}; + +/* +CONFIGURATION AREA - BUTTON DEFINITIONS +for a simple button, just define a primary colour +and an icon name from the icon array and +the text to display beneath the button +for toggle buttons, additionally provide secondary +colours, icon name and text. Also provide a reference +to a global variable for the value of the button. +The global variable should be declared at the start of +the program and it may be adviable to use the 'status_name' +format to ensure it is clear. +*/ + +var lightBtn = { + primary_colour: 0x653E, + primary_text: 'Lights', + primary_icon: 'light', + }; + +var socketsBtn = { + primary_colour: 0x33F9, + primary_text: 'Sockets', + primary_icon: 'switch', + }; + +var lightHallBtn = { + primary_colour: 0xE9C7, + primary_text: 'Hall Off', + primary_icon: 'light', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Hall On', + secondary_icon : 'light', + value: status_light_hall + }; + +var lightStudyBtn = { + primary_colour: 0xE9C7, + primary_text: 'Study Off', + primary_icon: 'light', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Study On', + secondary_icon : 'light', + value: status_light_study +}; + +var socketTVBtn = { + primary_colour: 0xE9C7, + primary_text: 'TV Off', + primary_icon: 'switch', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'TV On', + secondary_icon : 'switch', + value: status_tv + }; + +var socketPrinterBtn = { + primary_colour: 0xE9C7, + primary_text: 'Printer Off', + primary_icon: 'switch', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Printer On', + secondary_icon : 'switch', + value: status_printer +}; + +/* +CONFIGURATION AREA - SCREEN DEFINITIONS +a screen can have a button (as defined above) +on the left and/or the right of the screen. +in adddition a screen can optionally have +an icon for each of the three buttons on +the left hand side of the screen. These +are defined as btn1, bt2 and bt3. The +values are names from the icon array. +*/ +const homeScreen = { + left: lightBtn, + right: socketsBtn, +}; + +const lightsScreen = { + left: lightHallBtn, + right: lightStudyBtn, + btn3: "back" +}; + +const socketsScreen = { + left: socketTVBtn, + right: socketPrinterBtn, + btn3: "back" +}; + +/* base state definition +Each of the screens correspond to a state; +this class provides a constuctor for each +of the states +*/ +class State { + constructor(params) { + this.state = params.state; + this.events = params.events; + this.screen = params.screen; + } +} + +/* +CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS +This area defines how each screen behaves. +Each screen corresponds to a different State of the +state machine. This makes it much easier to isolate +behaviours between screens. +The state value is transmitted whenever a button is pressed +to provide context (so the receiving device, knows which +button was pressed on which screen). +The screens are defined above. +The events section identifies if a particular button has been +pressed and released on the screen and an action can then be taken. +The events function receives a notification from a mySetWatch which +provides an event object that identifies which button and whether +it has been pressed down or released. Actions can then be taken. +The events function will always return a State object. +If the events function returns different State from the current +one, then the state machine will change to that new State and redrsw +the screen appropriately. +To add in additional capabilities for button presses, simply add +an additional 'if' statement. +For toggle buttons, the value of the appropiate status object is +inversed and the new value transmitted. +*/ + +/* The Home State/Page is where the application beings */ +const Home = new State({ + state: "Home", + screen: homeScreen, + events: (event) => { + if ((event.object == "right") && (event.status == "end")) { + return SocketsMenu; + } + if ((event.object == "left") && (event.status == "end")) { + return LightsMenu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const LightsMenu = new State({ + state: "LightsMenu", + screen: lightsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_light_study.value = !status_light_study.value; + transmit(this.state, "study", onOff(status_light_study.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_light_hall.value = !status_light_hall.value; + transmit(this.state, "hall", onOff(status_light_hall.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const SocketsMenu = new State({ + state: "SocketsMenu", + screen: socketsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_printer.value = !status_printer.value; + transmit(this.state, "printer", onOff(status_printer.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_tv.value = !status_tv.value; + transmit(this.state, "tv", onOff(status_tv.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* translate button status into english */ +const startEnd = status => status ? "start" : "end"; + +/* translate status into english */ +const onOff= status => status ? "on" : "off"; + + +/* create watching functions that will change the global +button status when pressed or released +This is actuslly the hesrt of the program. When a button +is not being pressed, nothing is happening (no loops). +This makes the progrsm more battery efficient. +When a setWatch event is raised, the custom callbacks defined +here will be called. These then fired as events to the current +state/screen of the state mschine. +Some events, will result in the stste of the state machine +chsnging, which is why the screen is redrswn after each +button press. +*/ +const setMyWatch = (params) => { + setWatch(() => { + params.bool=!params.bool; + machine = machine.events({object: params.label, status: startEnd(params.bool)}); + drawScreen(machine.screen); + }, params.btn, {repeat:true, edge:"both"}); +}; + +/* object array used to set up the watching functions +*/ +const buttons = [ + {bool : bottom_btn, label : "bottom",btn : BTN3}, + {bool : middle_btn, label : "middle",btn : BTN2}, + {bool : top_btn, label : "top",btn : BTN1}, + {bool : left_btn, label : "left",btn : BTN4}, + {bool : right_btn, label : "right",btn : BTN5} + ]; + +/* set up watchers for buttons */ +for (var button of buttons) + {setMyWatch(button);} + +/* Draw various kinds of buttons */ +const drawButton = (params,side) => { + g.setFontAlign(0,1); + icon = drawIcon(params.primary_icon); + text = params.primary_text; + g.setColor(params.primary_colour); + const x = (side == "left") ? 0 : 120; + if ((params.toggle) && (params.value.value)) { + g.setColor(params.secondary_colour); + text = params.secondary_text; + icon = drawIcon(params.secondary_icon); + } + g.fillRect(0+x,28,119+x, 239); + g.setColor(0x000); + g.setFont("Vector",15); + g.setFontAlign(0,0.0); + g.drawString(text,60+x,160); + options = {rotate: 0, scale:2}; + g.drawImage(icon,x+60,120,options); +}; + +/* Draw the pages corresponding to the states */ +const drawScreen = (params) => { + drawButton(params.left,'left'); + drawButton(params.right,'right'); + g.setColor(0x000); + if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} + if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} + if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} +}; + +machine = Home; // instantiate the state machine at Home +Bangle.drawWidgets(); // draw active widgets +drawScreen(machine.screen); // draw the screen diff --git a/apps/_example_app/README.md b/apps/_example_app/README.md new file mode 100644 index 000000000..dc139bc9a --- /dev/null +++ b/apps/_example_app/README.md @@ -0,0 +1,25 @@ +# App Name + +Describe the app... + +Add screen shots (if possible) to the app folder and link then into this file with ![](.png) + +## Usage + +Describe how to use it + +## Features + +Name the function + +## Controls + +Name the buttons and what they are used for + +## Requests + +Name who should be contacted for support/update requests + +## Creator + +Your name diff --git a/apps/_example_app/add_to_apps.json b/apps/_example_app/add_to_apps.json index ca75a7bd8..1585ab73d 100644 --- a/apps/_example_app/add_to_apps.json +++ b/apps/_example_app/add_to_apps.json @@ -6,8 +6,9 @@ "version":"0.01", "description": "A detailed description of my great app", "tags": "", + "readme": "README.md", "storage": [ {"name":"7chname.app.js","url":"app.js"}, {"name":"7chname.img","url":"app-icon.js","evaluate":true} ] -} +} \ No newline at end of file diff --git a/apps/_example_widget/README.md b/apps/_example_widget/README.md new file mode 100644 index 000000000..a909e9e7e --- /dev/null +++ b/apps/_example_widget/README.md @@ -0,0 +1,25 @@ +# Widget Name + +Describe the app... + +Add screen shots (if possible) to the app folder and link then into this file with ![](.png) + +## Usage + +Describe how to use it + +## Features + +Name the function + +## Controls + +Name the buttons and what they are used for + +## Requests + +Name who should be contacted for support/update requests + +## Creator + +Your name diff --git a/apps/_example_widget/add_to_apps.json b/apps/_example_widget/add_to_apps.json index 5d0057960..527c698a0 100644 --- a/apps/_example_widget/add_to_apps.json +++ b/apps/_example_widget/add_to_apps.json @@ -7,6 +7,7 @@ "description": "A detailed description of my great widget", "tags": "widget", "type": "widget", + "readme": "README.md", "storage": [ {"name":"7chname.wid.js","url":"widget.js"} ] diff --git a/apps/_example_widget/widget.js b/apps/_example_widget/widget.js index 3893e3096..f7aed6991 100644 --- a/apps/_example_widget/widget.js +++ b/apps/_example_widget/widget.js @@ -3,7 +3,7 @@ currently-running apps */ (() => { function draw() { g.reset(); // reset the graphics context to defaults (color/font/etc) - // add your code + // add your code g.drawString("X", this.x, this.y); } diff --git a/apps/about/ChangeLog b/apps/about/ChangeLog index 2c81c0537..2a050c91e 100644 --- a/apps/about/ChangeLog +++ b/apps/about/ChangeLog @@ -2,3 +2,5 @@ 0.02: Update version checker for new filename type 0.03: Actual pixels as of 5 Mar 2020 0.04: Actual pixels as of 9 Mar 2020 +0.05: Actual pixels as of 27 Apr 2020 +0.06: Actual pixels as of 12 Jun 2020 diff --git a/apps/about/app.js b/apps/about/app.js index dc7b0cad8..4b4589262 100644 --- a/apps/about/app.js +++ b/apps/about/app.js @@ -29,5 +29,5 @@ g.drawString(NRF.getAddress(),120,232); g.flip(); // Pixel chooser image -g.drawImage(require("heatshrink").decompress(atob("+FQgl+xnu8AIBwGQgHuAoN3gF/hcLgEHu943G3gHdhvdDwIBCAAV3uEAhoBBhsO90OgHgoACBh0IhP5AAQZD8Hw+GwAwXn4AECxGAh0MEAOeJAMP3+/Lw0GswGEHgMM9gCBAIX//5PBhvQ7gJBxAAB9ng8vs5nMDgOg8HnOwIBBgBHDAAfQNAJBBgBQDgF4HQfd7veKoKbBO4Pr30IEAhgBAIIAG3oJDx+AQwLBBYgR3JsABCzOQzOeO4cP4HPc4QCBPoPN4HNO4QoB9wAByDvBO4L2COwZ4Gd4UP/7vEf4LvGKoUAooDB9x3FgEQI4TwBgEIN4NpwEMXILvBO4bvD/Y3BO46eDgGdO4n8CoXw+cQh/w/kNd4fodoXJhLvCKYJ4Dhe7AYJXFwBHBUAgABewMPhvQd4bwB8FQqDvHO4YADhH4B4XM9nABQTsCAAf/awbXBO4Vmd4xED57vD+EwFgOIBoUNxv/1////5zOAy8AvPN6AQCbQIiCOIIKB7EILwZIEO4YACKYlFoB3CHIZ2CAIJHBEAToCMwLvBAArvCAAnAAALvDAIIPByA5BEQUM/n8O4TzCAAQtBhvd/X8d4YYBvwOBO4bBFO4b2D4ASELoP/d4IbGABMBiINLV4YAD9LyFO5bvCYYfPCARKBmAcDh3ud4Wt7vdDgONwF8O4Q8Bh5jCBAOPO4o0BgFAAoLcB/4UBLIgBDAAPI5DeKIQIDChcLL4IABGIOAJITvHAAkGs0HgG7AAO99p3Dhi2N43N7rLCxGHgF56AHCRwUwAYIlBhsNGoR3CqALCh54CFAXHAIg/CRAIDBIgtHGIR3D3ZhCWwXQwA1CAAMP5/M/nPMhp3BwAJGWIQ7Dgczt1pzIHCa4IABhpkBOgQACD4ZRCs1m4AyEO4IBBABUMXYYZDgEEvoRFd4TwBO5IAJ5nAFAMNTYZEBGgRiD7p0CO4nM43JmZABAIICBAAOA+HwgUgkEiGxFsAQOwGQLeBhPpz2QChEO8AoCd4R5CdwZpCNgdVqq0B7vQ7vdMQWIbYJkFAAIjBEoR3DCoOA8A3CYAOvh/wgH/d4hVBd4VAgn/eIYAGX4cAgw2DNQ2e9I0DBgxIBxGAWgS1DAAZrBLAi2DeAJwDOoLcFNQOA5jbCd4gACO4OgAgMHu4aBDokKgGIZ4LtBogABBgXw4HwhnL5lwEQRmJb4bvBO4/uIAfQKAJ3Gh7sC6/XcgR3NDwR3DA4K4CAQJ3GV4JrBCoZuBAIMK1Wg4eAhwRB91AdpENdwbwEAAkHP5D8DPoIrBQ4LvMNYICDO4z7Bd5HM5jvD4DxBd4PQGwIBCHIMAeAQAEhQIC4GIboTfGT4JcBO4TvINQV2sDvCAAw6DRZIcB+APEhoxDACJ3BBZPwAAIsDhTwDXwbvFO5LvQhnMu1wNQoABBAMOM4RqDuFwY4IUEGpKUCcYPwAQIXEAAnu9wbJBQPg+ArCcoIBBhkMMoqCBO4IVBEYfuNYsNLISHDZYkM/93CgmIOwJtBh3uAIPuNQZ3BLwsOSYuIAIOABYPex2P9+JxncZAJcCO5VgXYRPCWQQzF4AABDohHB5gACBYPeSAYAHdwcJQYfc/OQIAQZBwB2BABQMBhiBBcQcP///AoLkBgH4+DvI1GKxGoFRVmXYThFAAwNFh0PawUNxoDC95fBDAsP+AnFFox3B9vtO4LvBG47/CcofOPoYABWIJ3Cd4jYBB4NwgwFBd4LxCIoQuGdwJIBdAoAHBoixBAQMJhvdBALuBBAJ3Gh/ADQkNLwboBAQLvDZAMP54ACMoJcCsAYC5nOV4OXcgQADd4QADs8HsF2g1QSwQAE+AcGRILhD/5cHMAgEFg2AzuNV4bvFhp3C5igN73u6DQBMwIAC/4/BcgaQDhwtBy8A3ewEAjvBAAdQgoCEDYbHCLgRIBeAwMCQoKdDwEMg6XBBgIXDO4WJhuNHQyOF+DvFAAwLB9vdVg7vJAAeXhYjHhGAAIKpL6CoBd4UDgbvDO44gDAYMHW4bCECIWdOoI2FKA0A0AABAwfu9oOFOwPgPI4ABWAICBE4p3KAARaBJQQDCAgJ3DdYLsEdwm3FwP/dwRiCd4nwQoYfDxEN7uIVxh3B1R3Bh0ONo/u93gAIIfMbozvY7oFELoMwA4h3CAAMJzOQAgOIO4LvG6ENAQP4xCjDAAiBBh6aBgEKd4139xNFd4SEBAAY6BhgHExAuG3ewO4zxCTBgnBAAMAgZKCEoo9EO4QAEdAIBBO4mPx5eBuCTDCYWfh/P6AeFNgVwg53EfITvC4BIB4B3HMgv/Vw3d7p3CFIPgHAwAMG4IAROwR1BAIWI/GAhm3gHMLAUAg1md4Q/Fh3uRgN3d4o+CPQPAAAWQ/7GB5nMH48DO4xDCF4YFCP4OAwD4GJgQCBhkJJQquGAwvAAQZsBAALvChfLuAICTKGIwBSDhoEB9yEBNwMM4GfgH8hnPO4wuBmB3ChYfFTYivBhAwBfAQABuA/GVAKKCADH4xHwhm8RYSICAALNIO4vQfgZfB8Hgd5H//gqBeYIrB5fLF4gAC6ENzIQBd453FYoUPO4ZUBCQMP/5SLuHwSg5UBAoggBxCiEJoe8714zUQCYbvBO4pDFXwRPBd4UOfwIzB5e7O44ABzP/LYp3CPAIHCu4XGhgiBBwR3IRQcP54ECyEJzJ3DkYUDGIIABRQTvJhvcZghFCu4XBZgRKGbQQAEO4m7hewGIIAEEJJjIKASKDNwh3Id4cJhJ5BOoMOgE9mAQCxGAd4jBHDAMN3p2Dd4Z+FSYThHhYDCnm8AgWwPAIVB/nM9nDO5kP//wBZD+DF4kPOoIBBC4rtCLwMO8EAgchd4w6JzwYBhHdegYkBO4oMDJwxKEgcAQgZ3D5//53Onk8O4a+BAIO62DbJwEJKIMIZoa1D+AABR4X/O4jvDO4PHyEQu0GfoIADegIAB5vmwGrd4YADSYMGy2WO4jODd4j5EAA52BMwLvB53uO4MNTIUBgIRB1WgCwXuEZYABg4EDHYI9CXAK6FLQcOO4IFBsACBGoMRgGHO4mJO4IAChkKyENNoTvFKwLGHhh5BhnMPoQEDBAnM5jvB4YIBFQUQ+EQd4vgV4LuDAAI0F6DUDO5eZzIFDO4TvDGYIBBd4OHw53BxR3E4GqyHA2ArBgwJBhe7XRH/O4UAhzONAAp3Bh8B+KWBAAnu8CRCAAVVgtQAoULeAq3GABOOSwp3DBIMICg0LW4MJyEIBoTvC38vYgeQyGZBYI3BfAx/DO5wcBSoLsDEILuBhn8BQdA+FAeIw/DBAbuDuEHf4adDbgQBB4IiF2ELbwQBBAwIMDEAuy+R3DOgJ4BO4vQIwfMGQJdB5nM55rELYo4CAAXvO4cIxDdEbw5MDO4n/PAMHAAQJCg/ud4UMAAYMCzOIwB3CEwWwO4oABJQbvFAAg3BHAPgFIKpDO4TgB//5RYIABjUAhUQeAYABxAeC7qWDABJXDOwYABBAsHu7vEAwIbD5h3FhKCBd45qD7ACB1StDBwK4CXY7vGO4cJzOZznMKgoUBO4g/BLYp5MO4sNO4UODYbuCKITvB54TBd453Fd48NhADBZwSnD/7aBh7KBOYZNNhx9CAAQoCO4uIOCIbCAAaiBI4Xg8AUGaoLvB4HwO4bzB34MBhI3BhZxBd4YGBd4t3agRCI7sNAAJsDAQMMN4oKB5jvEAAUNSIhkBh7tDAIcADQuIAALMBd4YBCh0JeAZ3G93Ah7RDAAO7+EJd4QAKd4IOB9x3LOwoADOwxJB5wgBhZHEAYq3B+Hw/8AuAIBAQScBDQQBBd4RtBF4OQAALvOzJ2DRATvCzJ3McQh3BhIfCZghrH7Z3CPAZEC+P4ZwwAHh7vBh/wg4ABTgpRBAIPuEwXteAhlEAAkL3YEC/PwAgW5VoYAGFIYACJ4nMRYIxCc4vMNgUJm4MBIoR3DhxFC/8QDAYiBu7cBRIdwUwLvBAAp3DdwYlBNga3LAA7vHLIZmBBQYMEhGIAodVDwQfB7sNHAf/JgUJMIML7wGBMogACiMf/4VBhKZBuFwhgODuHQE4LwBgDvFCIO7hbNCYokNAgMLXYUPAAp4G+xPCd4vHvgSGPIbvEAAKVCGITwDUAcJ06uHEQSsFhZ3Cd4ZBCO4bqCuAJCO4ULhZ4Bd4Y7C4AqCCQQAK+B9B/9gIQ53FwBxEhAFB5ncDYIsMAA5CD8DCBAQQADd5AFB7ruCh7sBAIaQCAARMBhAzGd52ZzMAsx3CYAZFB5nMTQTMFBgOAJQPQBghYCAQJBBO5wAKIQNwg7vBO4buBABewAAK+DGime9L0DNoI2BeQXAWoZ2Ef4Z3ILAMJyG5IQKoD9wABgHN8F5f5wAGcgJ3GdocAgjuDABLvCdQcGAoh3Fh/vdIJ3CcQLbFPAgAD5ncgEKAIPdRoMJCoJCD/4CBEYIaB4HguGgKBYDGTAKBKfIYQBCQnwaoICCd49gsDKGzLvHKYQADxAIC8HuAQINDd4Wg0HQ5j4ByAaEHoTvFO4OwMouYmcwh//AIIKDhByGZgZ3Bg7dBgxoFCAWACYjoDh7uBgwGDBocN5YfFhz1Bg4GCxOAd5B3BOILwBd4PMZJQAOxEwRoJFCqACBxw3DAASEEd4I7BAwQ4Sd46OCLQIAHO4cIH4R2BPAwAHgYIHhpODO55qBMwMI9HoeYZBC5kM4DvEZ4XAxGAg93zLeC3ew2DwFdwIFEO4kJFoRxDFoQFDBwMA8B2ChjrBAAaAFyBeBAA3QzOZOxQrBUoLvDVYXdSIR3DhnMAALvC6Hgd4YQCIAXwgELfCMPqAcCuF3O4l3AwgAF4AABIQJ3HyYCB1MK7gOCYwOQB4cMNYP/WoYMByDtBBAQHBhv9/p3FOwXMeAK6ChKMCKYV5U4Z3Bd4bqDAAZ3F81wdA14KQggEd4ZlBhn8Qg7vCyGQ6EMgF3O4LvLhQEDxEIMAOgO4MPDQJ3G553DABC4EO4zvM8HgFoQAB+CiBHoIgCAQbwFPQcAgjvHSgPQCINwvvQgEJhe7AAIbBhIWCGARrCwACBKoPd+H9DQJ3DGgPMVwfHyBwEO4ziDWoLvJCgXw9wDBO4f/gHcSYcMDwT0CAAgJDolANAPpeQgfBDQNwuDvD2CaC4HACALuEd4iRB7vzO4MIhEHJITwCZIMMvLYIgf/+RwBaoLWBAYQAHhwLBd4YACqHwAILlFAILyHPAUEAAIkBTIQAGO4QXDO4wAJdQMN7vddwOIg93XIXMhxRBdwIcJ+Hw/7iChnsBgkNhsMHoUOCAJ3BegQABgtVNQwzBAYMLWYIADO4VAOwNAd4oAEKwR3GgEJWwaREVAS6EAA4PCOA7KEO4QDBAIIjBSIPMDYxyDhaCBb4zvJ9wAE2C4CO4IAGFQPgLoVt5nODoJ3B3YTGWQhnIBQkMQoSGMAAwXCh///5/BNgJtC7q9D2HQ2G9BAT/BhLDChgfCCYYADSwZ3I93gAIJ3FABMO7wECCoJmMhkN7o2ChOQzOQcgQAD3ewKYJVFg93u9wEgp3Dd4R6CVYXA2GQgyLCfhTvHyBZCO5vvvaVBD4QkE9wRE/5mDAQR3BhoWCOgIBBAA2q0D3Md4IOMABBPDO5DvGO47YIh8O+65GNAQRF/7dFgHMd4mIwABBQoISEBAMOAAUA8DjDAA/MAYRAF7rxCABsPd5oAN995Z4mAwHM4AQF/+IO4wAGyDvFepB3BgBhCNYNwg93hGIgHAGoUHCwibDoAeDagQXBAIIRCC4h3EgxRLXQQLIhDUBO4cIhZ3Bd44AFzJxDCIMM/IxEd4kNDIsHg8IAgJ3DeAt3AoJiBRIUO9zFDJwIAB2BIJ8C2JIogMJwBBEAAMwaQoAQHBYAChruBd4QHB5iBECgzaCN4MMCQTvF35mGQYR3Ex2wAYP8O4gvG9ns8GIwEMO4cLeAQlCO4hNHAAS4CHAQaBhgACd4sOuHnd4RdDdwYBBCwK+GRIOIJALuBSQUPIQV3DIIABhGZwB3EP4UGRAjXEhp9CdQruI9x4BDIPgEwUA3YABNwQAC4GQHIOwV4QAUUIRpBAwUGKwLvCxjvGVgVwTYIfDBgJvExx3Cd4gBCAAPdpxjCHwigBhLwCBQnuUoVQHARqBAARCDhn5DQIABDIUEYAbnFABDuCAAIJEDIUM5iPKO4tAgGQMIbvGhwACdwR/Dd4MHu48Bh5oCAAkOd4cwbogEBdwgABdwLvJIAJCCdxjvEP4NgB4mIDpF3AAJBCHoZ3EBQTvDc4TwDBIh1BO4X/O44FEfgLvEO4JuHQIQoBd4Z3Gh8Pdw4ABdwqWGS5LuEADp3CBQ/uCpLvH5n5eASQBSIuIaIsP+BCOMoUIDwcIhGIO6DFDABpLEuAhC/4ABDJpXBhe7gG7dw4AC8AABaAjPIAAmgdZoDCAoX8ShIJEzOZXAetFZTDFX4f/FZHP/ieQFQgrFO4g2HTQOqEBLpBeAPAPonAAwTNBKwnvd5Pb6ADB9wACFALDBIALEGAA71C4EMVBAAMFIcLO4o0EKgMPhcz9zEKOIMMHYI8DXAcHg8AxApCIwIHBAAzvEOIUAu9wO40IO5EJzIoBd4p3Fh3dAwg7Eh6TCuDFEhxRDd4uu3QFBokEoEA9RHCY4J1BhnMHYbvCuGAvAPBeoZlBH4V3GYOOXgsOFAJNBO4YSB+/3MgPMhJLBJoUJ/JvFgcAmAHE93QOoZtBAQSKDhcIeAKHIgHA53u93qeAVAAAJWB1wRDd4wAEsEIO4MGs1mu4ABHQQCBhHIO4wDB2GwG4Pu8BRBv9/CwMM/ON6ABBd4h3KhzvEOgMHAQKeBO4TvGIwQAD5nA8Hg92u1R3BAITwEd4Z3Hg0GgGIgB2BO4d2IITvJO4ZDEKQKRCd40P/+QGwsiAwsOd4hnCOAQbBKYLuLMoJFB9w=")),0,135); +g.drawImage(require("heatshrink").decompress(atob("+FQgl+xnu8AIBwGQgHuAoN3gF/hcLgEHu943G3hwUCDwIBCAAV3uEAhoBBhsO90OgHgoACBh0IhP5AAQXBg8H8Hw+GwEAXn4AECxGAh0MEAOeJAMP3+/huIG4cMg1mMog8BhnsAQIBC///J4MN6HcBIOIAAPs8Hl9nM5gcB0Hg852BAIMAI4YACIIIACh8AKAcAvA6D7vd7wTBTYJ3B9e+hEAhA4CyHuy8HXw29NgIABx+ASQKsBYgR3DgHQCIXMsEAAIOZyGZzx3Dh/A57IDPoXN4HNHwQoB9wAByDvBO4LhDOwR4Fd4cP/4oB0DWCd45VCgFFAYPuO4QACgEed4PweAILBN4NpwEMXILvBO4bvD/f/d4cPCYJ1BAAKSCzp3E/hNBJwPziEP+H8hrvD9DtC5MJd4RTBGoLvBhe7BQJSBAAeAI4IoCO4T2Ch8N6DvDeAPgqFQd48MiB3BE4cI/AvC5ns4AKCdgQAD//wUwMMhhgBO4Nmd4xED57vD+EwFgKTCYoON/+v////OZwGXgF55vQI4TaBEQRxB6Hw7DRCAAPgO44ACKYlFoB3CHIcAiEAi93I4JpCdARmBd4IAFd4QAE4HA5//hh1BAIIPByA5BEQUM/n8O4TzCAAQtBhvd/X8d4YYBvwOBO4LvBYIoKBh/YewfA6B3DLoP/d4JXGABMBiKkEAAwKH9LyFO4fwOoR3Dd4TDD5/AJQcwDgcO9zvC1vd7ocBxuAvh3CuEHh5jCEoOPgHf/53CGgMAoGgbgX/CgJZEAIYAB5HIbxRCBAYULhZfBAAMA/GA/47Bd44ABh4CBg1mg8A3YAB3vtO4cMWxvG5vdZYWIw8AvPQd4NwRwUwAYIlBhsNGoR3CqB3BIAR4BFAXHAIg/CRAIDBIgtHHIR3D3ZhCZYXwwBrCOAXP5n855kNO4OABIyxCHYcDmdutOZA4VAAYUNqB0DAAQfDKIVms3AAgJ3BhBMBJwgAHhi7DDIQABgl9CIrvCeAJ3JABPM4AoBhqbDIgI0CMQfdOgR3E5nG5MzIAIBBAQIABwA5BgUgkEiEAe7hwECtgCB2B3BbwMJ9OeyBLIh3gFATvCPITuDhoCEgFVqq0B//w///MQWIbYJkFAAIjBEoR3DCoOA8A3CYAOvh/wE4LvEKoLvCoEE/7xDAAy/C2G+gw2DNQ2e9I0DBgxIBxGAWgS1DAAfd7pYE6BrBWwUIh2OAwLcGNQOA5jbCd4gACO4OgAgMHu4aBDokKgGIZ4LtBogABBgXw4HwhnL5lwEQXgd4V3BAIdBb4jvBO4/uIAfQKAJ3Gh7sC6/X7ogBUIL0BCwJ3ChHoO4QeCO4YHBXAQCBO4xQBJoYVBNwIBBhWq0HDwEOCIPuoDtIH4LuCAAOwMIR3BUATnIfgZ9BFYKHBd5nQKwICBBYWAPoJ3B///d5HM5jvD4DxBd4PQGwIBCHIMAeAQAEhQIC4GIboQABB4ifBW4ZeCAAO+EwJyBNQV2sDvCAAw6DAAaLFDgPwB4kNGIUJ5I3CcooAHO4OZzILH+AABFgcKeAa+Dd4p3Jd4+Ld4juChnMuz0DNQQABBAMOM4RqDuFwY4IUEGpLwB8DjB+ACBC4kJyAEC93uyAABDoxLB8HwFYTlBAIMMFIJlEQQJ3BCoIYBDgULCIpZCQ4YGBu5pBhn/u4UExB2BNoMO9wBB9xqDO4JeEEQKTFxABBwHJh3ex2P9+JxncZAJcBhMJO4mZO4dgXYRPCWQQzF4AABRIhHB5gACBYPeSAcAxOAAYICCdwK0CQYfc/I6BNYeAOwIAKBgMMQIIHC8EP///AoLkBgH4+AMCd4uoxWI1B3EAAOQzIDBswCBcIwAGBosOh7dChuNAYXvL4IPChGYgEP+AnFFox3B9vtO4LvBG47/CcofOPoYABWIIzCd4bYCB4NwgwFBd4IBBhI0Bh64CdwIHBdwJIBdAq7BEgTwDAgaxBAQMJhvdBALuBBAIQDeAMPh/ADQOH2+IhpeDfgbvDZAMP54ACMoJcCsAYC5nOV4OXcgQADd4QADs8HsF2g1QSwQAE+AcGRILhD/5cDE4ySDAgcGwGdxqvDd4j3BCIMP5iSCvfQcA6SB9wLBxBmBAAX/H4LkDSAcOFoOXgG72AgEd4IADqEFAQkL93rhzHCLgRIBCwbwCBgSFBOoLvBwEMg6XBBgIXDO4WJhuNHQyOF+DvCu+w2/QHoQACBYPt7qsCAAPgOQLvJAAeXhYdCZYIBBKYOAAII/I3yMB6CoBd4UDgbvDO44gBPIQ+BW4YADD4TvBOoI2FKA0A0AABAwfu9oOFOwPgAQLgBDoqwBAQIJFO5QACJIP/JQIDC+AVCO4LrBdgjuE24uB/7uFd4nwQob0DxEN7uIVxJ3E1R3Bh0ONoZ+E93gAIIPCVQ7fDgENAwRhC8AWBE4LvNAAXdaQsAmAHEO4QABhOZyB6BxB3BIg3QH4PQ/GIEIIAGQIMPTQMAhTuB1DaE9xNCAQTvCLgQACyDcDAAWIFARbD3ew9ycEKILvCABkMAAMAgZKCAAYlBHog8BAArqDO4mPx5bBuCTDCYWfh/P6AeFNgVwg7FEaITvC4BIB4B3HMgXdEwP/VwyCBO4QpB8A4GABiUCACB2COoIBCxH4wEM28A5hYCgEGszvC6F3NojKBuF3O4g+DPQPAAAWQ/7GB5nMH48D+AsCAAZDBF4YFCP4OAwD4GJgQCBhkJBYg8BBQJeBCgoABBAQCBNgIABd4UL5dwBASZQxGAKQcNAgPuQgJuBhnAz8A/kM553GFwMwO4PPhYfFTYjvBhAwBfAQABuA/GVAKKCTgxdR/GI+EM3gXCSIZeBg8Au7vEO4vQJgIAB+BTB8DvI//8FQLzBFYPL5YDBKQvQd5Z3FYoUPO4ZUBCQOf/5YDVoIFDIwNw+CUHBgQADEAOIUQnHg9wg+8714zUQCYbvBO4pDFXwRPBd4UOfwIzB5e7U4gAMO4R4BA4S4HhgiBO452DRQcP54ECyEJzJ3DkYXDGIIABRQTvCVoI0EhvcZghFCu4QBaQhKEdYIIFO4m7hewGIIRFEJAAFMYRQCRQZ3FXYUOCYXgd4cJhJ5BBIMOgE9mAYCxGAd4kAdwJ3DzIYBhu9OwbvDPwqTCcI8LAYU83gEC2B4BCoP85ns4Z6BO5UP/5lCAAz+DF4kPOoIBBC4eggGpdoJeBh3ggEDkLvGHROeDAMI7rFETYLVB3ew6AMDJwxKEgcAQgZ3D5//53Onk8O4a+BAIO62DvIKQMJKIMIZofQh3uOQIABR4X/BgLtBd4h3B4+QiF2gzjCeggAB5vmwGrd4YADSYMGy2Wd4jODd4j5EAA52BMwLvB53uO4MNTIUBgIRB1TOBAAJlBABkHJAXgHYI9CXAK6Cbwvghx3BAoNgAQI1BiMAw53ExJ3BAAUMhWQhptCd4T3DNwzGBhh5BhnMPoQEDBAnM5jvB4YIBFQUQ+EQd4plBFYZLCGgvQuDvCO4/gdoWZzIWDO4TvDGYIBBxGLw+HO4OKO4nA1WQ4GwFYMGBIML3a6I/53CgEOZxoAFO4MPgPxSwIAE93gSIQACqsFqEMF4MLeAbjFW4UA0ABCAAmOSwp3Dxe7hAiGha3BhOQhANCd4W/l7EDyGQzILBG4L4GP4Z3ODgKVBLgYhBL4MM/kA/LcBoHwoCAF6HueALdBh3+eAQABuEHcgKdFbgQBB4JtD3YAGgGwUoIiDAYTdB2Xy2DiCOgJ4BO4vQPYfMGQJdB5nM55rELYg9CA4fvO4cIxEAzJoBh4uBO4sLH4QOBC4X/PAMHAAQSCg/ud4UMAAYMCzOIwB2GO4oABJQbvFAAg3BHAPgFIKpDO4TgB//5zML1cAjUAhUQeAYABxAeC7qWDAALvCAAfAK4bbB92QAAJCFg93d4gGBAgSVBO4sJxbvI2EIBwPYAQOqVoYOBXAICDbI5YDO4cJzOZznMhQiCKYXQO4PMCQLCBLYorIABGQhp3CewTvDKIbvB54TBd453Hd4sNPQWZGITnDbQMPX4jLFABEONQMK3QGBFAR3Cg8Gd4JwRDYRwDUQJHC8HgCg2wd4XA+B3DeYO/BgMJxDvHhYMBd4l3agRCI7sNAAJEEFgLtCJ4nM5gbGhqRBg9gMgUPdoYBDfwIaExAABwDvEAIUOhIBBQAMJAYJ3D93Ah7RDAAO7+ARBEQgADBAbvBAoPuO48OW4R2FAAZ2GCoPOEAMLX4gDCNYTvB+Hw/8AuAIBAQScBDQQBBG4SoBF4OQAALvDO4ZQCd4eZOwbDCd4WZwEPGwQAL7p3BhOQDALMBQQPgNY/bO4R4DCAXx/DOGAAZnBAAMPd4JCBg4ABTgo4BAIPuEwXteAhlDJgOQd4UL3YMC/PwAgW52EJ/grDh//O4IpDeQ0A5iLBGIOwc4ZBB5nAG4OZm71BIoR3DhyrC/8QEgYiBu50BRIdwUwLvBAAp3DdwYlBEwS3CACLvGO4fM5h3CBQIpDgEIxAFDqoeCD4PdhvQRYOA//w8CsBMIML7zaCMoYACiMfF4PwX4OQuFwdgZ3B6BgBeAMAd4oRB3cLVgLFFhoEBha7Ch8PhAABAgJ4G+ycCd4vHvjBBVIZ5Ed4gABSoQxChsIdYWQ8HphOnVw4iCT4hQBO4TvDMYR3DdQVwBIR3ChcLPALvDHwXAFQQSCABXwPoP/sBCHO4SMCwBxEhAFB5ncDYIsMEoKFCa4YDC8DCBAQOZ5nMBILvIAoPdH4UPdgIBDSAQACJgMIHYzvDdoQADBweZzMAsx3CKgZIBIofAMAoMBwBKB6AMELAQCBIIIAKXRGZ/6YDIQNwg7vBO4buBABewAAK+DGh4AEz3pegZtBGwLyC4C1DOwj/DO5BYBhOQ3JCBh7LBgHuAAMA5vgvI9HVAKpCABDkBO4ztDgEEdwYAJd4TqDgwFEO4sP95ABO4TiBbYp4EKoncgEKAIPdRoMJCoJCDbYQjBDQPA8Fw0BQLAYyYBAAuIwAABg75DCAISE+DVBAQTvHsFgZQ2Zd45TCGwgIC8HuAQINDd4Wg0HQ5j4ByAaEHoTvFO4OwMouYmcwh//AIIKDYgYADh4IBPIMHg7dBgxoFCAMAwACBEIgACdwMGAwYWDhvLD4sOeoMHAwWJwDvIO4JxBeALvB5jdKABf4RAOImCNBKoVQAQOOG4YAC/5UBd4Y7BBYQ4Sd4sPj6OCLQIAHO4cIH4R2BPAwAChcOXYMMgYNHhpODAA7XBO4rvBMwMI9HoeYZBC5kM4AGBd4TPC4D5Cu+Zh5iB3ew2HP5nAdAbwBAocP+J3ChItCOIYtCAoYOBgHgOwUMdYIADBIOw8Fw6GQLwIAG6GZzLvKFYJ6Bd4arC7qRCO4cM5gABAwIyB8DvDCARKC+C8BAgP//4GBABEBiJ3BqAcCuF3O4l3AwgAF4AABIQJ3Ch7wDyYIB1MK7gOCYwOQDgcMNYP/NwQMCyDtBBAQHBhv9/p3FOwTZBXQcJx3ugF3uEHvKnDO4LvDdQYADL4kP81wdA14KQmwcoq3CAQP8BYfweATvCyGQ6EMI4J3Bd5UAhQEDxEIdoOgO4MPDQJ3GMIPILQhEB8BXCJQR3EGpIAFh/g8AtCLwQlBHoIgCAQbwFPQcAggLEd4SUB6ARBuF96EAhML3YABDYMJCwQwCNYWAAQJVB7vw/oaBO4Y0B5iuD4+Qhx3Kh4DCWoIGBh7tCAgIUE+HuAYJ3D/8A7iTDhgeCegQAEBIdEoBoB9IIDO4PcDQNwuDvD2CaC4HACALuEd4iRB7vzO4JTBg5JCeAXohEMvLvGAgMD//yOALVBBgIDCAA8OBYLvDAAVQ+ABBcooBBeQ54CggABEgKZCQYgABO4QXDO4wAJdQMN7vddwOIg93XIXMh3gwDuBLgQ3CNoJdB+Hw/7iChnsFIkNhsMHoUOCAJ3BegQABgtVNQwnBAYMLWYIADNgVAOwNAd4UN5pfFKwR3GgEJgBkBLIX/VoKoCXQgAHB4QAFOAPwLYIBBO4QDBAIIjBSIPMDYxyDhaCBb4zvJ9wAE2C4BeAKlFO40AtvM5wdBO4O7fgg+BH4JJCM5ByEhjjEAA4KBBg4XCh//UoRsBNoXdPIWw2HQ2G9BAIYBhcJYYIFBD4TRCAAiWDO4sAyALCUgZ3DAA94vEO70AzOQK4JmH6BfEhvdFAUDmEzmDkCAAe72BTBKosHu93VYIAENwKOBd4R6CVYXA2GQgyLCfhTvHLYJ3Bd5IAD997SoNwhCJDEgPuCIn/MwItBAQR3BhoWCOgIBBAA2q0BaBKRLvCGggABCZTqEAwsIDojvGaYTvGAA0Ph33uELg94BYjKECIP/boMNAwPe6HMd4Q8BxGAAIKFBeAgIBh2OMoXgcYIAJ5jvCfQvdeIQANh7vLGRbvEvOQW4JeBwGA5jLG/+IMgXtOwImHmDvFyB5ExAkCIQIbCNYNwg93hGIgHA4CIBg4gETYdAA4SHBEAIXBAIIRCC4h3EgyOKhi6CBIsIaIICCO4cIQYP/d4S8B9x3HmZ4BIIcM/IMDd4sNDIsHg6uBO4QJCeAl3AoJiBRIUO9wLBYoJOBAAOwPAoAD8C2EAAY8BVIJEC7oPHwBBEbwQmEaYXnSgwAGHAojFHwbuBd4QHB5iBEGwzaCN4MMCQTvF34qFhyDCO4MJ/kAx2wBAP8hvQ5h2CPoLXD9ns8GIwEMKYcLeAR2EJooAHXAR3CDQMMAATvFh1w87vCLobuDAIJ3EXwaJBxBIBdwKSCh5CCu4ZBAAMIzOAO4h/CgxxBPAJ2BL4XQhoGBYxI/F9x4BDIPgEwUA3YABNwToDyB4B2CvCACihGg8GKwLvCxjvGVgVwTYIYDBgIYBd4Z3Cd4JxBOALwD7tOMYQ3EUAMJeAQKE9ylCqA4CNQIACIQcM/IaBAAIZCgjADJANgAIQAIuEDmEwmZPBDIsM5iPKO4tAgGQMIbvEAAMOAATuCBATvCg93uB3BNAQAEhzvDmDdEAgLuEAALuBd5JABwFng53JdwsIWINwCYuIMAQACQAV3AAJBCHoZ3EBQTvB7vQc4UOhqlDd4R1BO4X/O44FEfgLvEO4JuHQIQoBd4Z3Du5jBh8PdwwDCmDBB8BKEDwYfCA4bNBSQ+IhMJhSWBACp3CAoSfBIoXuCpLvH5n5eASQBSIuIaIMPvIGBh/wE5J3Bd4RlCLoeIBQOIO5sIO4WoFQ7xBdgICBhrdFuAhC/4ABA4IABDotm5nMgBXBhe7gG7dwSrH8AABaAgBBg6gBABGgAwruEdYQDCAoX8HgJ3CAAnwd4qLD1orGAAbDFAAUP/4rBP4J3E5/8s3uO4IAIwB7CFQgrFO4QoBGw6aB1QoJbIKiBNwR3C4HAhhABJYkP94UB6GQD4vbTgXuAATJC8BABYgwAHeoI1Bhh3DQwIABoBNDhbwINAZ3EGgpUBh8LmfuYhRxBhg7BhgIC/gDCg8HgGIFIRGBA4IAGd4hxCgF3uB3GhB3IhOZFALvC5h3DoFPgjkB7sA2AcCHYkPSYVwYokOKIbvF126AoNEgigB9RHCUAJ1BdARsCewVwwF4WAYvBMoI/Cu4zBxwGB3cL2BxBFAJNBO4v3+/wVAOQJYJNChP5c4sDgEwgGEwB3B93QJoUHNoICCXYb7BeAIADYYvA53u93qeAVAAAJWB1wRDd4wAEsEIHIMGs1mu4ABHQQCBhHIAoOwAALvDAoI3B9x3Cv9/CwPPyGN6ABBd4h3HppOBhzvCMoR2BAQKxBO4TvGIwQAD5nA8Hg92u1QuCAILwEd4Z3Hg0GgGIgB2BO4d2sw+Bd4mwAIJ3FEQqRCd48P/+QO4kAkQFCojGCRQLdDGwJwCDYJTBdxZlBgB2BA==")),0,135); g.flip(); diff --git a/apps/accelrec/ChangeLog b/apps/accelrec/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/accelrec/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/accelrec/README.md b/apps/accelrec/README.md new file mode 100644 index 000000000..40d981b6a --- /dev/null +++ b/apps/accelrec/README.md @@ -0,0 +1,30 @@ +# Acceleration Recorder + +This app records a short period of acceleration data from the accelerometer +and + +## Usage + +* Start the `Accel Rec` App +* Select `Start` and place the Bangle with its rear face pointing downwards (screen up) +* After the counter counts down, it will display `Waiting` +* Now move the Bangle upwards (in the direction of `N`) + +At this point the 2 second recording will start at 100 samples per second, +with a maximum of 8g. + +After the 2 seconds you'll see a graph with calculated maximum acceleration +and velocity. + +* Press BTN2 (labelled `FINISH`) +* Not choose `Save` and choose a slot, from 1 to 6. Slots already used +are marked with a `*` + +## Getting data + +* Go to the App Loader: https://banglejs.com/apps/ +* Click `Connect` up the Top Right +* Click `My Apps` +* Click the Downward pointing arrow next to `Acceleration Recorder` +* After it loads, you'll see the recorded Acceleration values +* You can now either save them to a CSV file, or delete them diff --git a/apps/accelrec/app-icon.js b/apps/accelrec/app-icon.js new file mode 100644 index 000000000..2ed8bee20 --- /dev/null +++ b/apps/accelrec/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AC1rAAQrrF9QuHF8tBoIvsFwIwIF04wHF1AwGF1IwFF1QwDF0llGBAuki0QiwvnFwoABGAqMlFwQABSQbqmL44umX44uoSQS7oGRAukRAouqdAoubiwAFnaMDFwQABXbk6FxRfJF0y/HF1CSCdTwuOdTpjGF1gACF11rtYuKnYvhsowKncWF8K+BGBAuBF8IiBGBAuCF8YwHFwYvf4XCz06GAwuEF7283nB4IwEegJoDF8G74XO5owBEoo2CF8PI53O4O8ZJIufF4PI4QEBF5LteFQIADBo6QBFzwvDBxc6F74A/AH4A/AFQ")) diff --git a/apps/accelrec/app.js b/apps/accelrec/app.js new file mode 100644 index 000000000..5fb91e2e4 --- /dev/null +++ b/apps/accelrec/app.js @@ -0,0 +1,169 @@ +var acc; +var HZ = 100; +var SAMPLES = 2*HZ; // 2 seconds +var SCALE = 5000; +var THRESH = 1.01; +var accelx = new Int16Array(SAMPLES); +var accely = new Int16Array(SAMPLES); // North +var accelz = new Int16Array(SAMPLES); // Into clock face +var accelIdx = 0; +var lastAccel = undefined; +function accelHandlerTrigger(a) {"ram" + if (a.mag*2>THRESH) { // *2 because 8g mode + tStart = getTime(); + g.drawString("Recording",g.getWidth()/2,g.getHeight()/2,1); + Bangle.removeListener('accel',accelHandlerTrigger); + Bangle.on('accel',accelHandlerRecord); + if (lastAccel) accelHandlerRecord(lastAccel); + accelHandlerRecord(a); + } + lastAccel = a; +} +function accelHandlerRecord(a) {"ram" + var i = accelIdx++; + accelx[i] = a.x*SCALE*2; + accely[i] = -a.y*SCALE*2; + accelz[i] = a.z*SCALE*2; + if (accelIdx>=SAMPLES) recordStop(); +} +function recordStart() {"ram" + Bangle.setLCDTimeout(0); // force LCD on + accelIdx = 0; + lastAccel = undefined; + Bangle.accelWr(0x1B,0x03 | 0x40); // 100hz output, ODR/2 filter + Bangle.accelWr(0x18,0b11110100); // +-8g + Bangle.setPollInterval(10); // 100hz input + setTimeout(function() { + Bangle.on('accel',accelHandlerTrigger); + g.clear(1).setFont("6x8",2).setFontAlign(0,0); + g.drawString("Waiting",g.getWidth()/2,g.getHeight()/2); + }, 200); +} + + +function recordStop() {"ram" + console.log("Length:",getTime()-tStart); + Bangle.setPollInterval(80); // default poll interval + Bangle.accelWr(0x1B,0x0); // default 12.5hz output + Bangle.accelWr(0x18,0b11101100); // +-4g + Bangle.removeListener('accel',accelHandlerRecord); + E.showMessage("Finished"); + showData(); +} + + +function showData() { + g.clear(1); + var w = g.getWidth()-20; // width + var m = g.getHeight()/2; // middle + var s = 12; // how many pixels per G + g.fillRect(9,0,9,g.getHeight()); + g.setFontAlign(0,0); + for (var l=-8;l<=8;l++) + g.drawString(l, 5, m - l*s); + + function plot(a) { + g.moveTo(10,m - a[0]*s/SCALE); + for (var i=0;imaxAccel) maxAccel=a; + vel += a/HZ; + if (vel>maxVel) maxVel=vel; + } + g.reset(); + g.setFont("6x8").setFontAlign(1,0); + g.drawString("Max Y Accel: "+maxAccel.toFixed(2)+" g",g.getWidth()-14,g.getHeight()-50); + g.drawString("Max Y Vel: "+maxVel.toFixed(2)+" m/s",g.getWidth()-14,g.getHeight()-40); + //console.log("End Velocity "+vel); + g.setFont("6x8").setFontAlign(0,0,1); + g.drawString("FINISH",g.getWidth()-4,g.getHeight()/2); + setWatch(function() { + showMenu(); + }, BTN2); +} + +function showBig(txt) { + g.clear(1); + g.setFontVector(80).setFontAlign(0,0); + g.drawString(txt,g.getWidth()/2, g.getHeight()/2); + g.flip(); +} + +function countDown() { + showBig(3); + setTimeout(function() { + showBig(2); + setTimeout(function() { + showBig(1); + setTimeout(function() { + recordStart(); + }, 800); + }, 1000); + }, 1000); +} + +function showMenu() { + Bangle.setLCDTimeout(10); // set timeout for LCD in menu + var menu = { + "" : { title : "Acceleration Rec" }, + "Start" : function() { + E.showMenu(); + if (accelIdx==0) countDown(); + else E.showPrompt("Overwrite Recording?").then(ok=>{ + if (ok) countDown(); else showMenu(); + }); + }, + "Plot" : function() { + E.showMenu(); + if (accelIdx) showData(); + else E.showAlert("No Data").then(()=>{ + showMenu(); + }); + }, + "Save" : function() { + E.showMenu(); + if (accelIdx) showSaveMenu(); + else E.showAlert("No Data").then(()=>{ + showMenu(); + }); + }, + "Exit" : function() { + load(); + }, + }; + E.showMenu(menu); +} + +function showSaveMenu() { + var menu = { + "" : { title : "Save" } + }; + [1,2,3,4,5,6].forEach(i=>{ + var fn = "accelrec."+i+".csv"; + var exists = require("Storage").read(fn)!==undefined; + menu["Recording "+i+(exists?" *":"")] = function() { + var csv = ""; + for (var i=0;i + + + + +
+ + + + + diff --git a/apps/aclock/ChangeLog b/apps/aclock/ChangeLog index 98e3da8e7..9687bc58f 100644 --- a/apps/aclock/ChangeLog +++ b/apps/aclock/ChangeLog @@ -6,3 +6,5 @@ 0.09: center date, remove box around it, internal refactor to remove redundant code. 0.10: remove debug, refactor seconds to show elapsed secs each time app is displayed 0.11: shift face down for widget area, maximize face size, 0 pad single digit date, use locale for date +0.12: Fix regression after 0.11 +0.13: Fix broken date padding (fix #376) diff --git a/apps/aclock/clock-analog.js b/apps/aclock/clock-analog.js index 7b60a728f..951145c4e 100644 --- a/apps/aclock/clock-analog.js +++ b/apps/aclock/clock-analog.js @@ -1,7 +1,3 @@ -// eliminate ide undefined errors -let g; -let Bangle; - // http://forum.espruino.com/conversations/345155/#comment15172813 const locale = require('locale'); const p = Math.PI / 2; @@ -88,7 +84,7 @@ const drawDate = () => { const dayString = locale.dow(currentDate, true); // pad left date - const dateString = (currentDate.getDate() < 10) ? '0' : '' + currentDate.getDate().toString(); + const dateString = ("0"+currentDate.getDate().toString()).substr(-2); const dateDisplay = `${dayString}-${dateString}`; // console.log(`${dayString}|${dateString}`); // center date diff --git a/apps/activepedom/ChangeLog b/apps/activepedom/ChangeLog index fb0bc78e5..ca26a648a 100644 --- a/apps/activepedom/ChangeLog +++ b/apps/activepedom/ChangeLog @@ -1,2 +1,4 @@ 0.01: New Widget! -0.02: Distance calculation and display \ No newline at end of file +0.02: Distance calculation and display +0.03: Data logging and display +0.04: Steps are set to 0 in log on new day \ No newline at end of file diff --git a/apps/activepedom/README.md b/apps/activepedom/README.md index 055a91f56..a2a351a12 100644 --- a/apps/activepedom/README.md +++ b/apps/activepedom/README.md @@ -1,4 +1,4 @@ -# Active Pedometer +# Active Pedometer Pedometer that filters out arm movement and displays a step goal progress. I changed the step counting algorithm completely. @@ -6,6 +6,8 @@ Now every step is counted when in status 'active', if the time difference betwee To get in 'active' mode, you have to reach the step threshold before the active timer runs out. When you reach the step threshold, the steps needed to reach the threshold are counted as well. +Steps are saved to a datafile every 5 minutes. You can watch a graph using the app. + ## Screenshots * 600 steps ![](600.png) @@ -16,7 +18,7 @@ When you reach the step threshold, the steps needed to reach the threshold are c * 10600 steps ![](10600.png) -## Features +## Features Widget * Two line display * Can display distance (in km) or steps in each line @@ -30,6 +32,23 @@ When you reach the step threshold, the steps needed to reach the threshold are c * Steps are saved to a file and read-in at start (to not lose step progress) * Settings can be changed in Settings - App/widget settings - Active Pedometer +## Features App + +* The app accesses the data stored for the current day +* Timespan is choseable (1h, 4h, 8h, 12h, 16h, 20, 24h), standard is 24h, the whole current day + +## Data storage + +* Data is stored to a file named activepedomYYYYMMDD.data (activepedom20200427.data) +* One file is created for each day +* Format: now,stepsCounted,active,stepsTooShort,stepsTooLong,stepsOutsideTime +* 'now' is UNIX timestamp in ms +* You can use the app to watch a steps graph +* You can import the file into Excel +* The file does not include a header +* You can convert UNIX timestamp to a date in Excel using this formula: =DATUM(1970;1;1)+(LINKS(A2;10)/86400) +* You have to format the cell with the formula to a date cell. Example: JJJJ-MM-TT-hh-mm-ss + ## Settings * Max time (ms): Maximum time between two steps in milliseconds, steps will not be counted if exceeded. Standard: 1100 diff --git a/apps/activepedom/app.js b/apps/activepedom/app.js new file mode 100644 index 000000000..ec9b1237f --- /dev/null +++ b/apps/activepedom/app.js @@ -0,0 +1,165 @@ +(() => { + + //Graph module, as long as modules are not added by the app loader + Modules.addCached("graph",function(){exports.drawAxes=function(b,c,a){function h(a){return e+m*(a-t)/x}function l(a){return f+g-g*(a-n)/u}var k=a.padx||0,d=a.pady||0,t=-k,w=c.length+k-1,n=(void 0!==a.miny?a.miny:a.miny=c.reduce(function(a,b){return Math.min(a,b)},c[0]))-d;c=(void 0!==a.maxy?a.maxy:a.maxy=c.reduce(function(a,b){return Math.max(a,b)},c[0]))+d;a.gridy&&(d=a.gridy,n=d*Math.floor(n/d),c=d*Math.ceil(c/d));var e=a.x||0,f=a.y||0,m=a.width||b.getWidth()-(e+1),g=a.height||b.getHeight()-(f+1);a.axes&&(null!==a.ylabel&& + (e+=6,m-=6),null!==a.xlabel&&(g-=6));a.title&&(f+=6,g-=6);a.axes&&(b.drawLine(e,f,e,f+g),b.drawLine(e,f+g,e+m,f+g));a.title&&(b.setFontAlign(0,-1),b.drawString(a.title,e+m/2,f-6));var x=w-t,u=c-n;u||(u=1);if(a.gridx){b.setFontAlign(0,-1,0);var v=a.gridx;for(d=Math.ceil((t+k)/v)*v;d<=w-k;d+=v){var r=h(d),p=a.xlabel?a.xlabel(d):d;b.setPixel(r,f+g-1);var q=b.stringWidth(p)/2;null!==a.xlabel&&r>q&&b.getWidth()>r+q&&b.drawString(p,r,f+g+2)}}if(a.gridy)for(b.setFontAlign(0,0,1),d=n;d<=c;d+=a.gridy)k=l(d), + p=a.ylabel?a.ylabel(d):d,b.setPixel(e+1,k),q=b.stringWidth(p)/2,null!==a.ylabel&&k>q&&b.getHeight()>k+q&&b.drawString(p,e-5,k+1);b.setFontAlign(-1,-1,0);return{x:e,y:f,w:m,h:g,getx:h,gety:l}};exports.drawLine=function(b,c,a){a=a||{};a=exports.drawAxes(b,c,a);var h=!0,l;for(l in c)h?b.moveTo(a.getx(l),a.gety(c[l])):b.lineTo(a.getx(l),a.gety(c[l])),h=!1;return a};exports.drawBar=function(b,c,a){a=a||{};a.padx=1;a=exports.drawAxes(b,c,a);for(var h in c)b.fillRect(a.getx(h-.5)+1,a.gety(c[h]),a.getx(h+ + .5)-1,a.gety(0));return a}}); + + const storage = require("Storage"); + const SETTINGS_FILE = 'activepedom.settings.json'; + var history = 86400000; // 28800000=8h 43200000=12h //86400000=24h + + //return setting + function setting(key) { + //define default settings + const DEFAULTS = { + 'cMaxTime' : 1100, + 'cMinTime' : 240, + 'stepThreshold' : 30, + 'intervalResetActive' : 30000, + 'stepSensitivity' : 80, + 'stepGoal' : 10000, + 'stepLength' : 75, + }; + if (!settings) { loadSettings(); } + return (key in settings) ? settings[key] : DEFAULTS[key]; + } + + //Convert ms to time + function getTime(t) { + date = new Date(t); + offset = date.getTimezoneOffset() / 60; + //var milliseconds = parseInt((t % 1000) / 100), + seconds = Math.floor((t / 1000) % 60); + minutes = Math.floor((t / (1000 * 60)) % 60); + hours = Math.floor((t / (1000 * 60 * 60)) % 24); + hours = hours - offset; + hours = (hours < 10) ? "0" + hours : hours; + minutes = (minutes < 10) ? "0" + minutes : minutes; + seconds = (seconds < 10) ? "0" + seconds : seconds; + return hours + ":" + minutes + ":" + seconds; + } + + function getDate(t) { + date = new Date(t*1); + year = date.getFullYear(); + month = date.getMonth()+1; //month is zero-based + day = date.getDate(); + month = (month < 10) ? "0" + month : month; + day = (day < 10) ? "0" + day : day; + return year + "-" + month + "-" + day; + } + + //columns: 0=time, 1=stepsCounted, 2=active, 3=stepsTooShort, 4=stepsTooLong, 5=stepsOutsideTime + function getArrayFromCSV(file, column) { + i = 0; + array = []; + now = new Date(); + while ((nextLine = file.readLine())) { //as long as there is a next line + if(nextLine) { + dataSplitted = nextLine.split(','); //split line, + diff = now - dataSplitted[0]; //calculate difference between now and stored time + if (diff <= history) { //only entries from the last x ms + array.push(dataSplitted[column]); + } + } + i++; + } + return array; + } + + function drawGraph() { + //times + // actives = getArrayFromCSV(csvFile, 2); + // shorts = getArrayFromCSV(csvFile, 3); + // longs = getArrayFromCSV(csvFile, 4); + // outsides = getArrayFromCSV(csvFile, 5); //array.push(dataSplitted[5].slice(0,-1)); + now = new Date(); + month = now.getMonth() + 1; + if (month < 10) month = "0" + month; + filename = filename = "activepedom" + now.getFullYear() + month + now.getDate() + ".data"; + var csvFile = storage.open(filename, "r"); + times = getArrayFromCSV(csvFile, 0); + first = getDate(times[0]) + " " + getTime(times[0]); //first entry in datafile + last = getDate (times[times.length-1]) + " " + getTime(times[times.length-1]); //last entry in datafile + //free memory + csvFile = undefined; + times = undefined; + + //steps + var csvFile = storage.open(filename, "r"); + steps = getArrayFromCSV(csvFile, 1); + first = first + " " + steps[0] + "/" + setting('stepGoal'); + last = last + " " + steps[steps.length-1] + "/" + setting('stepGoal'); + + //define y-axis grid labels + stepsLastEntry = steps[steps.length-1]; + if (stepsLastEntry < 1000) gridyValue = 100; + if (stepsLastEntry >= 1000 && stepsLastEntry < 10000) gridyValue = 1000; + if (stepsLastEntry > 10000) gridyValue = 5000; + + //draw + drawMenu(); + g.drawString("First: " + first, 10, 30); + g.drawString(" Last: " + last, 10, 40); + require("graph").drawLine(g, steps, { + //title: "Steps Counted", + axes : true, + gridy : gridyValue, + y : 60, //offset on screen + x : 5, //offset on screen + }); + //free memory from big variables + allData = undefined; + allDataFile = undefined; + csvFile = undefined; + times = undefined; + } + + function drawMenu () { + g.clear(); + g.setFont("6x8", 1); + g.drawString("BTN1:Timespan | BTN2:Draw", 20, 10); + g.drawString("Timespan: " + history/1000/60/60 + " hours", 20, 20); + } + + setWatch(function() { //BTN1 + switch(history) { + case 3600000 : //1h + history = 14400000; //4h + break; + case 86400000 : //24 + history = 3600000; //1h + break; + default : + history = history + 14400000; //4h + break; + } + drawMenu(); + }, BTN1, {edge:"rising", debounce:50, repeat:true}); + + setWatch(function() { //BTN2 + g.setFont("6x8", 2); + g.drawString ("Drawing...",30,60); + drawGraph(); + }, BTN2, {edge:"rising", debounce:50, repeat:true}); + + setWatch(function() { //BTN3 + }, BTN3, {edge:"rising", debounce:50, repeat:true}); + + setWatch(function() { //BTN4 + }, BTN4, {edge:"rising", debounce:50, repeat:true}); + + setWatch(function() { //BTN5 + }, BTN5, {edge:"rising", debounce:50, repeat:true}); + + //load settings + let settings; + function loadSettings() { + settings = storage.readJSON(SETTINGS_FILE, 1) || {}; + } + + drawMenu(); + +})(); \ No newline at end of file diff --git a/apps/activepedom/widget.js b/apps/activepedom/widget.js index d569716ec..ed91a4cfd 100644 --- a/apps/activepedom/widget.js +++ b/apps/activepedom/widget.js @@ -3,13 +3,14 @@ var startTimeStep = new Date(); //set start time var stopTimeStep = 0; //Time after one step var timerResetActive = 0; //timer to reset active + var timerStoreData = 0; //timer to store data var steps = 0; //steps taken var stepsCounted = 0; //active steps counted var active = 0; //x steps in y seconds achieved var stepGoalPercent = 0; //percentage of step goal var stepGoalBarLength = 0; //length og progress bar var lastUpdate = new Date(); //used to reset counted steps on new day - var width = 45; //width of widget + var width = 46; //width of widget //used for statistics and debugging var stepsTooShort = 0; @@ -18,13 +19,42 @@ var distance = 0; //distance travelled + const s = require('Storage'); const SETTINGS_FILE = 'activepedom.settings.json'; const PEDOMFILE = "activepedom.steps.json"; + var dataFile; + var storeDataInterval = 5*60*1000; //ms let settings; - //load settings + //load settings function loadSettings() { - settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {}; + settings = s.readJSON(SETTINGS_FILE, 1) || {}; + } + + function storeData() { + now = new Date(); + month = now.getMonth() + 1; //month is 0-based + if (month < 10) month = "0" + month; //leading 0 + filename = filename = "activepedom" + now.getFullYear() + month + now.getDate() + ".data"; //new file for each day + dataFile = s.open(filename,"a"); + if (dataFile) { //check if filen already exists + if (dataFile.getLength() == 0) { + //new day, set steps to 0 + stepsCounted = 0; + stepsTooShort = 0; + stepsTooLong = 0; + stepsOutsideTime = 0; + } + dataFile.write([ + now.getTime(), + stepsCounted, + active, + stepsTooShort, + stepsTooLong, + stepsOutsideTime, + ].join(",")+"\n"); + } + dataFile = undefined; //save memory } //return setting @@ -39,8 +69,8 @@ 'stepGoal' : 10000, 'stepLength' : 75, }; - if (!settings) { loadSettings(); } - return (key in settings) ? settings[key] : DEFAULTS[key]; + if (!settings) { loadSettings(); } + return (key in settings) ? settings[key] : DEFAULTS[key]; } function setStepSensitivity(s) { @@ -77,20 +107,20 @@ //Remove step if time between first and second step is too long if (stepTimeDiff >= setting('cMaxTime')) { //milliseconds - stepsTooLong++; //count steps which are note counted, because time too long + stepsTooLong++; //count steps which are not counted, because time too long steps--; } - //Remove step if time between first and second step is too short if (stepTimeDiff <= setting('cMinTime')) { //milliseconds - stepsTooShort++; //count steps which are note counted, because time too short + stepsTooShort++; //count steps which are not counted, because time too short steps--; } + //Step threshold reached if (steps >= setting('stepThreshold')) { if (active == 0) { stepsCounted = stepsCounted + (setting('stepThreshold') -1) ; //count steps needed to reach active status, last step is counted anyway, so treshold -1 - stepsOutsideTime = stepsOutsideTime - 10; //substract steps needed to reac active status + stepsOutsideTime = stepsOutsideTime - 10; //substract steps needed to reach active status } active = 1; clearInterval(timerResetActive); //stop timer which resets active @@ -109,14 +139,17 @@ function draw() { var height = 23; //width is deined globally - distance = (stepsCounted * setting('stepLength')) / 100 /1000 //distance in km + distance = (stepsCounted * setting('stepLength')) / 100 /1000; //distance in km //Check if same day let date = new Date(); if (lastUpdate.getDate() == date.getDate()){ //if same day } - else { - stepsCounted = 1; //set stepcount to 1 + else { //different day, set all steps to 0 + stepsCounted = 0; + stepsTooShort = 0; + stepsTooLong = 0; + stepsOutsideTime = 0; } lastUpdate = date; @@ -166,7 +199,7 @@ stepsTooLong : stepsTooLong, stepsOutsideTime : stepsOutsideTime }; - require("Storage").write(PEDOMFILE,d); //write array to file + s.write(PEDOMFILE,d); //write array to file }); //When Step is registered by firmware @@ -182,8 +215,7 @@ }); //Read data from file and set variables - let pedomData = require("Storage").readJSON(PEDOMFILE,1); - + let pedomData = s.readJSON(PEDOMFILE,1); if (pedomData) { if (pedomData.lastUpdate) lastUpdate = new Date(pedomData.lastUpdate); stepsCounted = pedomData.stepsToday|0; @@ -191,12 +223,10 @@ stepsTooLong = pedomData.stepsTooLong; stepsOutsideTime = pedomData.stepsOutsideTime; } - pedomdata = 0; //reset pedomdata to save memory setStepSensitivity(setting('stepSensitivity')); //set step sensitivity (80 is standard, 400 is muss less sensitive) - + timerStoreData = setInterval(storeData, storeDataInterval); //store data regularly //Add widget WIDGETS["activepedom"]={area:"tl",width:width,draw:draw}; - })(); \ No newline at end of file diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index 2ff60e658..23b8ee562 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -4,3 +4,7 @@ 0.04: Tweaks for variable size widget system 0.05: Add alarm.boot.js and move code from the bootloader 0.06: Change 'New Alarm' to 'Save', allow Deletion of Alarms +0.07: Don't overwrite existing settings on app update +0.08: Make alarm scheduling more reliable +0.09: Add per alarm auto-snooze option +0.10: Fix auto-snooze option (this stopped new alarms being added) (fix #506) diff --git a/apps/alarm/alarm.js b/apps/alarm/alarm.js index 7f0027bc8..28261110a 100644 --- a/apps/alarm/alarm.js +++ b/apps/alarm/alarm.js @@ -24,9 +24,14 @@ function showAlarm(alarm) { }).then(function(sleep) { buzzCount = 0; if (sleep) { + if(alarm.ohr===undefined) alarm.ohr = alarm.hr; alarm.hr += 10/60; // 10 minutes } else { alarm.last = (new Date()).getDate(); + if (alarm.ohr!==undefined) { + alarm.hr = alarm.ohr; + delete alarm.ohr; + } if (!alarm.rp) alarm.on = false; } require("Storage").write("alarm.json",JSON.stringify(alarms)); @@ -38,6 +43,10 @@ function showAlarm(alarm) { Bangle.buzz(100).then(function() { if (buzzCount--) setTimeout(buzz, 3000); + else if(alarm.as) { // auto-snooze + buzzCount = 10; + setTimeout(buzz, 600000); + } }); },100); }); diff --git a/apps/alarm/app.js b/apps/alarm/app.js index 745a7e797..b6019ca08 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -8,6 +8,7 @@ var alarms = require("Storage").readJSON("alarm.json",1)||[]; msg : "Eat chocolate", last : 0, // last day of the month we alarmed on - so we don't alarm twice in one day! rp : true, // repeat + as : false, // auto snooze } ];*/ @@ -44,12 +45,14 @@ function editAlarm(alarmIndex) { var mins = 0; var en = true; var repeat = true; + var as = false; if (!newAlarm) { var a = alarms[alarmIndex]; hrs = 0|a.hr; mins = Math.round((a.hr-hrs)*60); en = a.on; repeat = a.rp; + as = a.as; } const menu = { '': { 'title': 'Alarms' }, @@ -70,6 +73,11 @@ function editAlarm(alarmIndex) { value: en, format: v=>v?"Yes":"No", onchange: v=>repeat=v + }, + 'Auto snooze': { + value: as, + format: v=>v?"Yes":"No", + onchange: v=>as=v } }; function getAlarm() { @@ -81,7 +89,7 @@ function editAlarm(alarmIndex) { // Save alarm return { on : en, hr : hr, - last : day, rp : repeat + last : day, rp : repeat, as: as }; } menu["> Save"] = function() { diff --git a/apps/alarm/boot.js b/apps/alarm/boot.js index 709703bdd..47dae5361 100644 --- a/apps/alarm/boot.js +++ b/apps/alarm/boot.js @@ -2,15 +2,16 @@ (function() { var alarms = require('Storage').readJSON('alarm.json',1)||[]; var time = new Date(); - var active = alarms.filter(a=>a.on&&(a.last!=time.getDate())); + var active = alarms.filter(a=>a.on); if (active.length) { - active = active.sort((a,b)=>a.hr-b.hr); + active = active.sort((a,b)=>(a.hr-b.hr)+(a.last-b.last)*24); var hr = time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600); if (!require('Storage').read("alarm.js")) { console.log("No alarm app!"); - require('Storage').write('alarm.json',"[]") + require('Storage').write('alarm.json',"[]"); } else { var t = 3600000*(active[0].hr-hr); + if (active[0].last == time.getDate() || t < 0) t += 86400000; if (t<1000) t=1000; /* execute alarm at the correct time. We avoid execing immediately since this code will get called AGAIN when alarm.js is loaded. alarm.js @@ -21,4 +22,4 @@ },t); } } -})() +})(); diff --git a/apps/analogimgclk/ChangeLog b/apps/analogimgclk/ChangeLog new file mode 100644 index 000000000..864afc91e --- /dev/null +++ b/apps/analogimgclk/ChangeLog @@ -0,0 +1,2 @@ +0.01: New App! +0.02: Add BTN2 -> launcher diff --git a/apps/analogimgclk/app-icon.js b/apps/analogimgclk/app-icon.js new file mode 100644 index 000000000..e9c28da6b --- /dev/null +++ b/apps/analogimgclk/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkGswA/AFEiAAMoCqcykWEDQQWW0YYNsQXCn8//8zDgMiwwWNmf/CwICCDAUmIpYWD+YYFkIuKkYTBCogGCmUhGBAuBn4QBF4wJBiR6IFwYRCFoYBCVZBGBRQIYFFwaUBkUWFw4XKBIUhGAwXBEwYXFmcTBIMxC4pGBUgQXCLYc/kMvAgKqBSIheGGInyiQGCn8SC43zCwouDHQfzF4x2DFAgFCCwbaBSAi9CAAPxiMTRIcvEQIYCeQIXI+chiMSn8zGgJeDn8yiQXHBoMzDAMRiEzCwgXBF5IPCCwMQCoZUDYAhHFCQUBgIHFF5YRDkMDCwpfKAAn074UDC5QOHC48xL4jvDF5kznFGC4ovOmciwwXFWwIACB4M0C48hC4x4EC44kB+UYI4h4DGIhHEBIUyjAWEC4JIEF4VPF4shlAXFJAYQD+gXBEAcziReEGAg/F74ECBIIuHC4UhCAIZC+UzOokhkIXHJAMTDAQCGmOEkwXHGASSDAQk4oUSCxAwCiUjC4sooUhFxIYCkMilEzCwMymIgBRg5JGiUiwoDBlUijFCCxgYDIQIXCRZAAJJQIWBCqIA/AC4=")) diff --git a/apps/analogimgclk/app.js b/apps/analogimgclk/app.js new file mode 100644 index 000000000..99dace78e --- /dev/null +++ b/apps/analogimgclk/app.js @@ -0,0 +1,118 @@ +var bgimg = require("Storage").read("analogimgclk.bg.img"); + +function getImg(g, col) { + return { + width:g.getWidth(), + height:g.getHeight(), + bpp:1,transparent:0, + buffer:g.buffer, + palette:new Uint16Array([0,col])}; +} + +var handSizeMin = 90; +var handSizeHr = 60; +var handSizeSec = 96; +var gmin = Graphics.createArrayBuffer(12,handSizeMin*2,1,{msb:true}); +var gminimg = getImg(gmin, 0xFFFF); +var ghr = Graphics.createArrayBuffer(16,handSizeHr*2,1,{msb:true}); +var ghrimg = getImg(ghr, g.setColor("#E0E0E0").getColor()); +var gsec = Graphics.createArrayBuffer(6,handSizeSec*2,1,{msb:true}); +var gsecimg = getImg(gsec, g.setColor("#FF0000").getColor()); + +// create hand images +var c = gmin.getHeight()/2; +var o = 16; // overhang +gmin.fillCircle(6,6,6); +gmin.fillCircle(6,c+o,6); +gmin.fillRect(0,6,11,c+o); +c = ghr.getHeight()/2; +ghr.fillCircle(8,8,8); +ghr.fillCircle(8,c+o,8); +ghr.fillRect(0,8,15,c+o); +c = gsec.getHeight()/2; +gsec.fillCircle(3,3,3); +gsec.fillCircle(3,c+o,3); +gsec.fillRect(0,3,5,c+o); + +// last positions of hands (in radians) +var lastrmin=0, lastrhr=0, lastrsec=0; + +// draw hands - just the bit of the image that changed +function drawHands(full) { + var d = new Date(); + var rsec = d.getSeconds()*Math.PI/30; + var rmin = d.getMinutes()*Math.PI/30; + // hack so hour hand only moves every 10 minutes + var rhr = (d.getHours() + Math.round(d.getMinutes()/10)/6)*Math.PI/6; + var bounds = {}; + if (!full) { // work out the bounds of the hands + var x1 = (g.getWidth()/2)-10; + var y1 = (g.getHeight()/2)-10; + var x2 = (g.getWidth()/2)+10; + var y2 = (g.getHeight()/2)+10; + function addPt(ang, r, ry) { + var x = (g.getWidth()/2) + Math.sin(ang)*r + Math.cos(ang)*ry; + var y = (g.getHeight()/2) - Math.cos(ang)*r + Math.sin(ang)*ry; + //g.setColor("#ff0000").fillRect(x-2,y-2,x+2,y+2); + if (xx2)x2=x; + if (y>y2)y2=y; + } + function addSec(r) { + addPt(r,handSizeSec,5);addPt(r,handSizeSec,-5); + addPt(r,-(o+8),5);addPt(r,-(o+8),-5); + } + function addMin(r) { + addPt(r,handSizeMin,8);addPt(r,handSizeMin,-8); + addPt(r,-(o+8),8);addPt(r,-(o+8),-8); + } + function addHr(r) { + addPt(r,handSizeHr,8);addPt(r,handSizeHr,-8); + addPt(r,-(o+8),8);addPt(r,-(o+8),-8); + } + if (rsec!=lastrsec) { + addSec(rsec);addSec(lastrsec); + } + if (rmin!=lastrmin) { + addMin(rmin);addMin(lastrmin); + } + if (rhr!=lastrhr) { + addHr(rhr);addHr(lastrhr); + } + bounds = {x:x1,y:y1,width:1+x2-x1,height:1+y2-y1}; + } + + g.drawImages([ + {image:bgimg,x:24,y:24}, + {image:ghrimg,x:120,y:120,center:true,rotate:rhr}, + {image:gminimg,x:120,y:120,center:true,rotate:rmin}, + {image:gsecimg,x:120,y:120,center:true,rotate:rsec} + ],bounds); + lastrsec = rsec; + lastrmin = rmin; + lastrhr = rhr; +} + +if (g.drawImages) { + var secondInterval = setInterval(drawHands,1000); + // handle display switch on/off + Bangle.on('lcdPower', (on) => { + if (secondInterval) { + clearInterval(secondInterval); + secondInterval = undefined; + } + if (on) { + drawHands(); + secondInterval = setInterval(drawHands,1000); + } + }); + + g.clear(); + drawHands(true); +} else { + E.showMessage("Please update\nBangle.js firmware\nto use this clock","analogimgclk"); +} + +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); diff --git a/apps/analogimgclk/app.png b/apps/analogimgclk/app.png new file mode 100644 index 000000000..d234b54d4 Binary files /dev/null and b/apps/analogimgclk/app.png differ diff --git a/apps/analogimgclk/bg.img b/apps/analogimgclk/bg.img new file mode 100644 index 000000000..821ff709e Binary files /dev/null and b/apps/analogimgclk/bg.img differ diff --git a/apps/animals/ChangeLog b/apps/animals/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/animals/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/animclk/ChangeLog b/apps/animclk/ChangeLog new file mode 100644 index 000000000..7852105a0 --- /dev/null +++ b/apps/animclk/ChangeLog @@ -0,0 +1,2 @@ +0.01: New App! +0.02: Fix bug if image clock wasn't installed diff --git a/apps/animclk/V29.LBM.js b/apps/animclk/V29.LBM.js new file mode 100644 index 000000000..5b986d77d --- /dev/null +++ b/apps/animclk/V29.LBM.js @@ -0,0 +1,482 @@ +CanvasCycle.processImage({filename:'V29.LBM',width:640,height:480,colors:[[0,0,0],[219,247,255],[203,243,255],[175,235,255],[155,231,255],[131,223,255],[95,223,255],[95,215,255],[63,215,255],[47,207,255],[0,199,255],[23,191,255],[11,183,255],[31,175,255],[47,163,247],[47,151,239],[59,139,231],[63,127,219],[71,115,203],[147,203,255],[103,171,223],[67,123,143],[199,171,159],[179,215,171],[191,215,223],[183,223,239],[175,235,255],[155,211,231],[135,187,207],[151,207,167],[195,207,171],[199,171,159],[95,151,179],[95,151,179],[83,135,159],[71,119,139],[63,107,123],[59,103,115],[31,91,115],[47,99,119],[63,107,123],[67,123,143],[67,123,143],[67,127,147],[71,127,151],[71,131,151],[71,131,155],[75,135,159],[159,199,215],[31,103,123],[7,75,95],[0,71,87],[0,67,83],[0,67,83],[0,67,83],[0,71,91],[15,91,111],[31,103,127],[51,123,143],[63,131,151],[75,139,159],[87,151,167],[123,175,187],[163,199,207],[255,255,255],[255,255,255],[131,175,191],[111,155,175],[119,167,183],[139,179,195],[163,199,207],[191,215,223],[167,203,215],[191,215,223],[207,227,235],[215,231,239],[191,215,227],[231,243,247],[215,231,239],[231,243,247],[179,203,219],[167,191,207],[155,183,199],[143,175,191],[135,167,183],[123,159,175],[115,151,167],[119,155,171],[123,159,175],[127,163,179],[131,167,183],[139,171,187],[155,187,203],[179,203,219],[199,219,235],[223,239,255],[79,147,171],[59,131,155],[43,119,143],[31,107,131],[43,119,143],[59,131,159],[79,147,171],[99,163,187],[119,83,79],[211,159,135],[87,55,55],[55,31,31],[23,15,11],[115,71,63],[175,127,115],[231,179,155],[115,107,135],[159,139,155],[143,127,151],[191,167,187],[143,127,151],[115,107,135],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[247,247,251],[231,227,247],[207,215,243],[187,219,243],[195,211,231],[187,207,203],[91,91,91],[75,59,51],[75,59,51],[75,59,51],[79,71,71],[79,91,103],[99,107,123],[119,131,143],[143,151,163],[171,175,183],[179,191,195],[187,207,203],[187,207,203],[187,207,203],[187,207,203],[147,143,171],[183,151,175],[131,127,159],[131,127,159],[131,127,159],[159,147,179],[195,175,191],[111,95,115],[111,95,115],[123,103,123],[151,127,151],[111,95,115],[151,123,135],[203,167,175],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,239,231],[243,223,239],[231,199,223],[207,179,219],[187,171,211],[171,159,211],[155,151,215],[151,151,215],[155,159,219],[163,171,227],[175,191,247],[255,255,255],[255,255,255],[207,167,143],[147,103,95],[91,63,63],[71,51,51],[139,119,103],[91,71,63],[23,15,11],[215,171,155],[143,111,103],[119,91,83],[219,175,155],[143,111,103],[103,79,79],[79,59,59],[95,71,83],[111,91,111],[59,47,47],[99,75,67],[135,119,107],[63,51,51],[51,43,51],[95,71,83],[111,91,111],[79,59,59],[143,111,103],[203,175,163],[183,155,147],[255,239,227],[243,227,215],[235,215,203],[207,183,171],[179,155,143],[255,227,199],[243,211,183],[231,195,167],[219,179,151],[211,163,135],[199,147,123],[187,131,111],[179,119,99],[107,103,131],[215,171,155],[143,111,103],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[255,255,255],[11,11,11],[107,103,131],[219,219,235],[255,255,255]],cycles:[{reverse:0,rate:0,low:59,high:63},{reverse:0,rate:0,low:7,high:13},{reverse:0,rate:0,low:13,high:17},{reverse:0,rate:1227,low:32,high:47},{reverse:0,rate:1689,low:48,high:63},{reverse:0,rate:1689,low:64,high:79},{reverse:0,rate:1227,low:80,high:95},{reverse:0,rate:921,low:96,high:103},{reverse:0,rate:1689,low:128,high:143},{reverse:0,rate:1536,low:22,high:31},{reverse:0,rate:0,low:138,high:142},{reverse:0,rate:0,low:0,high:0},{reverse:0,rate:0,low:0,high:0},{reverse:0,rate:0,low:0,high:0},{reverse:0,rate:0,low:0,high:0},{reverse:0,rate:0,low:0,high:0}],pixels:[ +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,252,109,252,109,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,108,108,108,252,252,109,109,109,109,109,109,252,252,252,252,252,252,252,252,252,108,108,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,252,110,109,110,252,110,252,110,252,110,252,110,252,252,252,109,252,252,252,252,252,252,252,109,252,109,109,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,107,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,109,108,109,108,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,109,108,252,108,252,109,252,109,109,109,252,109,252,109,252,109,252,109,252,109,108,108,108,108,108,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,252,110,109,110,252,110,252,110,109,110,252,110,252,110,252,110,252,110,252,110,252,110,252,110,252,109,252,109,252,109,252,252,252,109,252,109,252,109,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,252,252,109,252,252,252,107,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,108,109,108,109,108,109,108,109,108,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,108,108,108,109,109,109,109,252,109,109,109,109,109,109,109,109,109,252,109,252,252,252,108,108,108,108,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,252,252,252,110,109,110,109,110,109,110,109,110,109,110,252,110,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,109,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,110,252,110,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,108,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,252,252,109,108,108,109,109,252,109,252,109,252,109,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,108,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,252,110,252,110,252,110,252,110,109,110,252,110,252,110,252,110,252,110,252,110,252,110,252,252,252,252,252,109,252,109,252,109,252,110,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,110,252,110,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,108,109,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,108,109,108,109,108,109,109,109,108,109,252,109,109,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,109,109,109,109,252,109,109,109,109,109,109,109,252,109,252,109,252,108,108,108,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,252,110,109,110,109,110,109,110,252,110,109,110,252,110,252,110,252,252,252,110,252,252,252,252,252,252,252,109,252,109,252,110,252,252,109,252,109,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,110,252,252,252,110,252,252,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,110,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,108,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,252,109,108,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,252,109,109,252,109,109,109,252,109,252,109,252,109,252,109,252,109,109,109,252,109,252,109,252,109,108,109,108,109,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,252,110,252,110,252,110,109,110,252,110,252,110,252,110,252,110,252,110,252,110,252,109,252,252,252,109,252,109,252,109,252,110,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,108,109,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,108,109,109,109,109,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,108,109,109,108,109,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,109,110,109,110,109,110,109,110,109,110,109,110,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,109,252,110,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,109,252,109,252,110,252,110,252,110,252,110,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,108,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,109,109,109,109,109,252,109,109,109,252,109,252,109,252,109,252,109,109,109,109,109,108,109,108,108,108,109,108,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,252,110,252,110,109,110,252,110,252,110,252,110,252,110,252,110,252,252,252,110,252,110,252,109,252,109,252,110,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,252,252,110,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,108,109,108,109,108,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,108,109,109,109,109,109,252,109,109,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,252,109,109,109,109,109,108,109,108,109,109,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,252,110,109,110,109,110,252,110,109,110,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,109,252,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,252,252,109,252,109,252,109,252,110,252,110,252,110,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,108,109,252,109,252,109,252,109,252,252,252,109,252,252,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,109,109,109,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,109,252,109,109,109,252,109,109,109,252,109,109,109,252,109,252,108,108,108,108,108,108,109,108,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,18,110,252,110,109,110,109,110,109,110,252,110,252,110,252,252,252,252,252,110,252,109,252,109,252,109,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,109,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,108,109,108,109,108,109,252,109,252,109,252,252,252,252,109,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,109,109,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,109,109,109,108,109,109,109,109,108,108,108,108,109,109,109,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,252,110,109,110,109,110,109,110,109,110,252,110,252,110,252,252,252,252,252,252,252,109,252,109,252,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,109,252,109,252,109,252,109,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,109,252,109,252,109,252,109,252,109,252,109,252,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,108,108,108,109,109,252,108,108,108,108,108,108,109,108,109,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,109,110,109,110,109,110,109,110,252,110,252,110,252,252,252,110,252,110,252,109,252,109,252,109,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,109,108,109,109,109,108,109,252,109,109,109,109,109,109,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,109,109,108,109,252,109,109,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,252,109,109,109,109,109,109,109,108,108,108,108,109,108,109,109,109,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,109,110,109,110,109,110,109,110,109,110,109,252,252,252,252,110,252,110,109,109,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,109,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,110,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,109,252,109,252,109,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,108,109,109,109,252,109,252,109,252,109,109,109,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,108,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,252,109,109,109,252,109,252,109,108,108,108,108,108,109,108,109,108,109,109,109,108,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,109,110,252,110,109,110,109,110,252,110,252,110,252,110,109,110,109,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,252,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,109,108,109,108,252,108,252,109,109,109,109,109,109,109,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,108,109,109,109,109,109,252,109,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,252,252,108,108,108,108,109,109,109,109,108,109,109,109,109,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,109,110,109,110,109,110,252,110,252,110,252,252,109,110,109,110,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,110,252,110,252,110,252,252,252,252,252,252,109,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,109,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,108,109,252,109,252,109,252,109,252,109,252,252,109,109,109,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,108,109,108,252,108,108,109,108,109,108,108,108,109,108,108,108,108,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,252,110,109,110,109,110,109,110,252,110,252,110,109,110,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,252,107,252,107,252,252,252,252,252,252,252,252,109,110,109,110,109,110,110,110,110,110,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,252,252,252,252,252,109,252,109,252,109,252,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,108,109,108,109,108,109,108,109,108,109,252,252,108,109,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,108,252,252,108,252,108,108,108,108,108,109,108,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,109,110,109,110,109,110,252,110,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,252,110,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,109,107,109,107,252,252,252,107,252,107,252,107,109,252,109,252,109,252,109,110,109,109,109,109,109,110,110,110,109,252,252,252,252,252,252,252,252,252,109,252,109,252,110,252,110,252,110,252,252,252,110,252,252,252,252,109,252,109,109,109,109,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,109,252,109,252,109,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,107,252,109,109,108,109,252,109,252,109,252,109,252,109,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,108,109,108,108,108,252,108,252,108,252,108,108,108,108,108,108,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,109,110,252,110,109,110,109,109,109,109,109,110,109,109,109,110,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,252,109,107,107,252,107,252,107,252,107,252,107,252,107,252,107,107,106,106,106,18,18,18,252,109,110,109,110,109,110,109,109,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,110,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,108,252,108,109,108,109,108,109,108,109,108,109,252,109,108,109,109,109,109,109,109,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,252,252,252,252,109,108,108,108,108,108,108,108,108,108,108,252,108,252,108,252,252,108,252,18,18,18,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,110,109,110,109,110,109,109,109,109,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,110,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,107,107,107,107,107,107,252,107,252,107,252,252,252,107,107,106,106,106,18,18,17,18,18,18,17,18,18,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,252,252,252,110,252,252,109,252,110,252,110,252,110,252,110,252,252,252,252,252,252,252,252,109,252,109,109,109,109,109,109,110,109,110,252,252,252,252,252,252,252,252,109,252,109,252,109,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,107,252,108,109,108,109,252,109,252,109,252,109,252,109,252,109,252,109,109,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,252,108,109,108,109,252,109,109,108,252,108,252,108,252,108,252,108,252,108,252,108,252,252,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,252,110,109,110,109,109,109,109,109,109,109,110,109,110,252,252,252,252,252,252,252,252,252,252,109,110,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,107,252,107,252,107,252,107,252,107,109,107,109,107,106,106,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,109,110,109,110,109,110,109,110,109,110,109,110,252,110,109,252,252,252,252,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,109,108,109,108,109,108,109,108,109,108,109,108,109,252,109,108,109,109,109,108,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,108,108,108,108,108,108,108,108,108,252,108,108,108,252,109,252,108,252,252,252,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,109,110,109,109,109,109,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,109,110,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,107,107,107,107,107,107,252,107,252,107,109,252,106,106,106,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,252,110,252,109,252,109,252,252,252,252,252,109,252,252,252,252,109,252,109,109,109,109,109,110,110,110,110,252,252,252,252,109,252,252,252,109,252,109,252,110,252,110,252,110,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,108,109,108,109,252,109,108,109,252,109,108,109,252,109,108,109,109,109,109,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,109,107,109,107,252,107,109,107,252,107,252,109,252,107,252,109,252,107,252,252,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,109,110,109,109,109,109,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,110,109,110,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,107,252,107,252,107,252,107,109,106,106,106,106,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,110,109,110,109,110,109,110,109,110,109,110,252,110,110,110,252,110,109,252,109,252,252,252,252,252,109,252,252,252,252,109,252,109,252,109,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,110,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,109,107,109,108,109,108,109,108,109,108,109,108,109,108,109,108,109,108,109,108,109,108,109,108,109,108,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,107,252,252,109,109,109,109,109,109,109,109,109,109,109,109,109,109,252,109,252,252,252,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,109,110,109,109,109,109,109,110,109,110,109,110,109,252,252,252,252,252,252,252,109,110,109,110,109,110,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,109,107,107,107,107,107,107,252,107,106,106,106,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,109,110,109,110,109,110,109,110,109,110,109,109,109,110,109,252,109,252,252,252,252,252,109,252,252,252,252,109,252,109,109,109,109,109,109,110,110,110,109,252,252,252,109,252,109,252,109,252,110,252,110,252,110,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,108,109,108,109,108,109,252,109,252,109,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,108,252,108,252,108,252,107,252,107,252,107,109,107,109,107,252,107,109,107,252,107,252,107,252,107,109,109,109,252,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,110,109,109,109,109,109,110,109,110,109,110,109,252,252,252,252,252,252,252,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,252,107,252,107,252,106,106,106,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,110,109,110,109,110,109,110,109,110,252,110,109,252,252,252,252,252,252,252,109,252,252,109,252,109,252,109,109,109,109,110,109,110,109,110,252,252,109,252,252,252,252,109,252,109,252,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,108,109,108,109,108,109,108,109,108,109,108,109,108,109,108,109,108,109,108,109,108,109,108,252,108,252,252,252,108,252,252,252,108,108,252,108,252,108,252,108,252,108,252,109,109,107,252,252,252,107,252,252,109,107,109,109,109,107,109,109,109,109,109,109,109,109,109,109,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,109,109,109,109,109,110,109,110,109,110,109,252,252,252,252,252,252,252,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,107,107,107,107,106,106,106,107,106,106,106,106,106,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,109,110,109,110,109,110,109,110,109,110,252,252,252,252,252,252,109,252,109,252,109,109,109,109,109,109,109,109,110,110,110,110,109,252,109,252,109,252,252,252,252,109,109,109,109,252,109,110,109,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,107,109,108,109,108,109,252,109,108,109,252,109,108,109,252,109,252,109,252,109,109,109,252,109,252,109,252,109,252,252,252,108,252,108,252,108,252,108,252,108,252,108,252,108,109,108,252,107,252,107,252,107,252,107,109,107,109,107,252,107,109,107,252,107,109,109,109,109,109,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,110,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,110,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,107,107,252,107,252,252,107,106,106,106,107,106,107,106,106,106,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,252,109,109,252,109,252,109,109,109,109,110,109,110,110,110,252,252,252,252,109,109,252,109,252,109,252,109,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,108,109,108,109,108,109,107,109,108,109,108,109,108,109,108,109,108,109,108,109,108,109,108,252,108,252,108,108,252,108,108,108,252,108,252,108,252,108,109,108,109,108,109,107,252,109,109,107,252,109,109,109,109,109,109,109,109,109,109,109,109,109,109,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,110,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,107,107,107,252,252,252,252,252,252,252,106,106,106,106,106,106,106,106,106,106,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,109,110,109,110,109,110,252,252,252,252,252,252,109,252,109,109,109,109,109,109,109,110,109,110,110,110,109,110,252,252,109,252,109,252,109,109,109,109,109,109,109,110,109,110,252,252,252,252,252,252,252,252,252,252,109,252,109,252,110,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,107,109,108,109,108,109,108,109,252,109,108,109,252,109,252,109,252,109,109,109,252,109,252,109,252,109,252,252,252,108,252,108,252,108,109,108,109,108,109,108,252,107,252,107,252,107,252,107,252,107,252,107,109,107,109,107,109,107,109,107,252,109,109,109,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,110,109,110,109,110,109,110,252,252,252,252,252,252,252,110,109,110,109,110,109,110,109,107,109,107,252,107,107,107,252,107,252,107,252,107,252,107,252,252,252,106,107,106,106,106,106,106,106,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,18,18,18,17,18,17,18,17,109,110,109,110,109,110,252,252,252,252,252,109,252,109,252,109,109,109,109,110,109,110,109,110,110,110,109,252,252,252,252,109,252,109,252,109,109,109,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,107,109,107,109,108,109,108,109,108,109,108,109,108,109,108,109,108,109,108,109,108,109,108,252,252,252,108,108,252,108,108,108,109,108,109,108,109,108,109,107,109,109,109,107,252,109,109,107,252,109,109,107,109,109,109,107,109,109,109,109,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,109,110,109,110,109,110,109,252,252,252,252,252,252,252,109,107,109,107,109,107,109,107,109,107,109,107,107,107,252,107,252,107,252,252,252,252,252,252,252,106,106,106,106,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,109,110,109,110,252,252,252,252,252,252,109,109,109,109,109,109,109,109,109,110,110,110,110,110,109,252,252,252,252,252,109,109,109,109,109,109,109,110,109,110,109,110,252,252,252,252,109,252,252,252,109,252,109,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,107,109,252,109,108,109,252,109,108,109,252,109,108,109,252,109,252,109,109,109,252,109,252,109,252,252,252,108,252,108,109,108,109,108,252,108,109,108,252,107,109,107,252,107,252,107,252,107,252,107,109,107,109,107,252,109,109,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,110,109,110,109,110,109,252,252,252,252,252,252,110,109,107,109,107,107,107,107,107,107,107,252,107,252,107,252,107,252,107,252,107,252,252,252,107,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,109,110,109,110,252,110,252,252,252,109,252,109,252,109,109,110,109,110,109,110,109,110,109,110,252,252,252,109,252,109,252,109,252,109,109,109,110,110,109,110,109,252,252,252,252,252,252,252,252,252,109,252,252,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,107,109,108,109,107,109,108,109,108,109,107,109,108,109,108,252,108,252,108,252,108,252,108,252,108,108,252,108,108,108,109,108,109,108,109,108,109,107,109,107,109,107,109,109,109,107,109,109,109,109,109,109,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,110,109,110,109,110,109,110,252,252,252,252,252,107,107,107,107,107,107,107,107,107,107,107,252,107,252,107,252,252,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,109,110,109,110,109,252,252,252,252,109,109,109,109,109,109,110,109,110,109,110,109,110,109,252,252,252,252,252,252,109,252,109,109,109,109,109,110,110,109,110,109,252,252,252,252,252,109,252,109,252,109,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,108,109,108,109,252,109,108,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,108,252,108,109,108,109,108,109,108,109,108,252,108,109,107,252,107,252,107,252,107,252,107,106,107,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,109,110,109,110,109,110,109,252,107,107,107,107,107,107,252,107,252,107,252,107,252,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,110,109,110,109,252,252,109,252,109,252,109,109,110,109,110,109,110,110,110,109,110,109,252,252,109,252,109,252,109,252,109,252,109,252,109,109,109,109,110,252,252,252,252,252,252,252,252,252,252,109,252,110,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,107,109,108,109,108,109,108,109,108,109,108,109,108,109,108,252,108,252,108,252,108,252,252,252,108,108,252,107,108,108,109,108,109,108,109,108,109,107,109,109,109,107,109,109,109,107,109,106,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,110,109,110,109,110,110,107,107,107,107,107,107,107,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,18,18,17,18,110,109,110,109,252,109,109,252,109,109,109,109,109,109,110,109,110,109,110,109,110,252,252,252,252,252,109,252,109,109,109,252,109,109,109,109,109,109,110,252,252,109,252,109,252,109,252,109,252,109,252,110,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,252,109,107,109,252,109,108,109,252,109,108,109,252,109,108,109,252,109,252,252,252,109,252,252,252,107,252,108,109,108,109,108,109,108,252,107,252,107,252,107,252,107,252,107,252,106,106,106,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,109,110,109,110,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,110,110,110,109,252,109,109,252,109,109,109,109,110,109,110,109,110,109,110,109,252,252,252,252,109,252,109,252,109,252,109,252,109,109,109,109,110,109,252,252,252,252,252,252,252,109,252,252,252,109,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,107,109,107,109,107,109,107,109,108,109,108,109,252,252,252,252,252,252,108,252,252,252,108,252,252,108,252,108,109,108,109,108,109,109,109,107,252,109,252,252,252,107,107,107,106,106,106,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,110,110,109,110,109,252,109,109,109,109,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,109,252,109,109,109,109,109,109,109,109,110,252,252,252,252,109,252,109,252,109,252,109,252,109,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,108,109,252,109,108,109,108,109,252,109,252,109,252,109,252,109,252,252,252,109,252,107,252,107,252,252,252,108,109,108,109,108,252,108,252,107,252,107,252,107,107,107,107,107,107,106,106,106,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,110,109,110,109,110,252,109,109,110,109,110,110,110,109,110,109,110,252,252,252,252,252,109,252,109,252,109,252,109,252,109,109,109,109,110,252,252,252,252,252,252,252,252,252,252,252,252,109,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,107,109,108,109,108,109,252,109,252,109,252,252,252,252,252,252,108,252,108,107,108,107,252,252,252,109,109,109,109,108,109,109,109,109,252,109,109,106,107,107,107,107,107,107,106,106,106,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,109,110,109,110,109,109,109,110,109,110,110,110,109,110,109,252,252,252,252,252,252,252,252,109,252,109,109,109,109,109,109,109,109,110,109,252,252,252,109,252,109,252,109,252,109,252,109,252,110,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,109,107,109,108,109,252,109,252,109,252,109,252,252,252,252,252,109,109,109,108,107,252,107,252,252,109,108,109,108,252,108,109,109,252,108,252,109,107,106,107,106,107,106,107,107,107,106,106,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,110,109,110,109,110,109,110,110,110,109,110,109,110,252,252,252,109,252,252,252,109,252,109,252,109,252,109,252,109,109,109,109,110,109,252,252,252,252,252,252,252,109,252,252,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,107,109,108,109,108,109,252,109,252,252,252,252,252,109,252,252,252,109,109,107,252,252,109,109,109,109,109,109,109,109,109,109,109,109,108,106,107,106,107,107,107,107,107,107,107,107,106,106,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,109,110,109,109,109,110,109,110,109,110,109,252,252,252,252,252,252,252,252,109,252,109,252,109,109,109,109,109,109,110,109,110,109,252,109,252,109,252,109,252,109,252,109,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,109,107,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,107,252,107,252,107,109,109,109,109,109,109,252,109,252,109,252,106,108,106,107,106,107,106,107,106,107,107,107,107,107,106,106,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,18,17,109,110,109,110,109,110,109,110,109,110,252,252,252,252,252,109,252,109,252,109,252,109,252,109,252,109,109,109,109,110,109,110,252,252,252,252,252,252,252,252,109,252,109,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,109,107,109,108,109,108,109,109,109,109,109,252,109,252,109,252,252,252,109,252,252,252,109,109,109,109,109,109,109,109,109,109,109,106,106,108,106,106,106,107,107,107,106,107,107,107,107,107,106,106,106,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,110,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,109,252,109,109,109,109,109,109,109,109,109,109,110,109,252,109,252,252,252,109,252,109,252,109,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,109,107,109,108,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,109,109,109,109,109,109,252,109,106,106,107,106,107,106,107,106,107,106,107,106,107,107,107,106,107,107,106,106,106,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,17,18,17,17,110,109,110,109,110,252,110,109,110,252,252,252,252,252,109,252,109,252,109,252,109,252,109,109,109,109,109,109,110,109,252,252,252,252,252,252,252,252,252,109,252,252,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,109,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,108,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,107,109,107,109,108,109,109,109,109,109,252,109,252,109,252,109,252,109,252,252,252,252,109,109,109,109,109,109,109,108,106,106,106,106,106,106,106,106,107,106,107,106,107,107,107,107,107,107,106,106,106,106,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,110,109,110,109,110,109,110,109,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,109,109,110,109,252,109,252,109,252,109,252,109,252,109,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,109,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,107,109,107,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,109,109,109,109,109,109,107,107,109,106,106,106,106,106,107,106,107,106,107,106,107,106,107,106,107,107,107,106,106,106,106,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,17,18,17,17,17,17,17,17,110,110,110,109,110,109,110,109,252,252,252,109,252,252,109,252,109,252,109,252,109,252,109,109,109,109,110,109,110,109,252,252,252,252,252,252,252,252,252,109,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,108,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,109,107,109,107,109,109,109,109,109,252,109,252,109,252,252,252,109,252,252,252,252,252,109,109,109,109,107,107,107,107,107,106,106,106,106,106,106,107,106,107,106,107,107,107,107,107,107,107,106,106,106,106,106,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,110,110,110,109,110,109,110,252,252,252,252,109,252,252,252,252,109,252,109,109,109,109,109,109,109,109,110,109,110,109,252,109,252,252,252,109,252,109,252,109,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,107,109,252,109,252,109,252,109,252,109,252,109,252,109,252,107,252,109,252,109,252,252,109,107,107,107,252,107,107,107,252,106,106,106,107,106,107,106,107,106,107,106,107,106,107,107,107,106,106,106,106,106,106,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,110,110,110,109,110,252,110,109,252,252,110,252,252,252,109,252,109,252,109,109,109,252,109,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,109,252,252,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,109,107,109,107,109,109,109,109,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,109,107,107,107,252,107,109,109,107,107,106,106,106,106,106,106,107,106,107,107,107,107,107,107,107,106,106,106,106,106,106,106,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,110,110,110,110,109,110,109,252,109,110,109,252,252,252,252,109,109,109,252,109,109,109,110,110,109,110,109,110,252,252,109,252,109,252,109,252,109,252,109,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,109,107,109,252,109,252,109,252,109,252,109,252,109,252,109,252,107,252,109,252,109,252,252,107,107,109,107,252,107,252,107,252,107,252,106,106,106,107,106,107,106,107,106,107,106,107,107,107,106,106,106,106,106,106,106,106,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,17,16,17,17,17,17,17,17,110,110,110,110,110,110,109,110,109,110,109,110,252,109,252,109,252,109,109,109,109,110,109,110,109,110,109,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,109,107,109,107,109,252,109,107,109,252,109,252,109,252,252,252,109,252,252,252,252,107,107,107,107,109,109,109,109,252,109,252,107,109,252,106,106,106,106,106,106,107,107,107,107,107,107,107,106,107,106,106,106,106,106,106,106,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,110,110,110,109,110,109,110,109,110,109,110,109,252,252,109,109,109,109,110,110,110,109,110,109,110,252,252,252,252,252,252,252,252,109,252,109,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,107,109,252,109,252,109,252,109,252,109,252,109,252,109,252,107,252,252,252,109,107,107,252,107,252,107,252,107,109,109,252,109,109,107,252,107,106,106,107,106,107,106,107,106,107,107,107,106,107,106,106,106,106,106,106,106,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,110,110,110,109,110,109,110,109,110,109,110,109,252,109,252,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,107,109,107,109,107,109,107,109,252,109,252,109,252,252,252,252,252,252,252,107,107,107,107,107,252,107,252,107,252,252,252,252,252,252,109,109,252,106,106,106,106,106,107,107,107,107,107,106,107,106,107,106,106,106,106,106,106,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,110,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,252,109,110,109,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,107,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,107,107,107,252,107,252,107,252,107,252,107,252,107,252,252,252,107,109,107,106,106,107,106,107,106,107,107,107,106,107,106,107,106,106,106,107,106,106,106,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,110,110,110,109,110,109,110,252,110,109,110,109,110,109,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,109,252,109,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,109,109,109,109,109,109,109,107,109,252,109,252,109,252,252,252,252,252,252,252,107,107,107,107,107,252,107,107,107,252,252,252,252,252,252,252,252,252,252,109,109,106,106,106,106,107,107,107,106,107,106,107,106,107,106,106,106,106,106,106,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,17,16,17,17,110,110,109,110,109,110,109,110,109,110,109,110,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,110,252,110,252,109,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,109,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,107,107,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,252,252,107,109,109,106,106,107,107,107,106,107,106,107,106,107,106,106,106,106,106,106,106,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,109,110,109,110,109,110,109,110,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,109,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,109,108,109,109,109,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,107,107,107,107,107,107,107,107,252,107,252,107,252,252,252,252,252,252,252,252,252,252,109,106,252,106,107,106,107,106,107,106,107,106,107,106,106,106,106,106,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,109,110,109,110,109,110,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,109,252,109,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,107,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,252,109,252,252,107,252,107,252,109,107,106,107,106,106,107,107,106,107,106,106,106,106,106,106,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,110,109,110,109,110,109,110,109,110,109,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,252,109,109,109,109,109,109,109,109,252,109,252,109,252,252,252,109,252,252,252,252,107,107,107,107,107,107,107,107,252,107,252,107,252,252,252,252,252,109,109,109,252,252,252,252,252,252,252,107,107,106,107,106,107,107,107,106,106,106,106,106,106,106,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,109,110,109,110,109,110,109,110,109,110,109,110,109,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,109,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,110,252,109,252,109,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,252,109,109,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,107,107,252,107,107,107,252,107,252,107,252,107,252,107,252,107,252,109,252,107,252,252,252,107,252,252,252,252,252,106,107,106,106,107,107,106,107,106,107,106,106,106,106,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,109,110,109,110,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,252,107,109,107,109,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,107,107,107,107,107,107,107,107,252,107,252,107,252,107,252,252,109,109,109,109,252,252,252,252,252,252,252,252,252,107,107,106,107,106,107,106,107,106,106,106,106,106,106,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,110,109,110,109,110,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,110,252,110,252,252,252,252,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,107,107,107,107,107,252,107,252,107,252,107,252,107,252,107,107,107,252,107,252,109,252,109,252,107,252,107,252,252,252,107,107,106,107,106,107,106,106,106,106,106,107,106,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,109,110,109,110,109,110,109,110,252,109,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,109,109,107,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,107,107,107,107,107,107,107,107,107,107,252,107,107,107,109,109,109,109,252,109,252,109,252,252,107,107,252,252,252,107,107,107,107,106,107,106,107,106,106,106,106,106,106,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,109,110,109,110,109,110,109,110,109,109,109,109,252,110,252,252,252,252,252,252,252,252,110,252,110,252,252,252,252,252,110,252,110,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,107,107,107,107,252,107,252,107,252,107,107,107,252,107,109,107,252,107,252,109,252,107,252,109,252,107,252,107,252,252,252,107,107,252,107,106,107,106,106,106,107,106,106,106,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,16,17,110,109,110,109,110,109,110,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,107,109,107,109,109,109,252,109,252,109,252,252,252,252,252,252,252,107,107,107,107,107,107,107,107,107,107,107,252,107,109,109,109,109,109,109,252,109,252,252,252,252,107,107,252,107,252,252,252,107,107,107,107,106,107,106,106,106,106,106,106,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,110,109,110,109,110,109,110,109,109,109,109,109,109,109,109,252,252,252,252,252,252,110,252,252,252,252,252,252,252,110,252,110,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,109,109,252,109,107,109,252,109,252,109,252,109,252,109,252,109,252,252,252,107,107,107,252,107,107,252,252,252,252,252,109,109,109,109,252,109,107,107,252,107,252,109,252,109,252,252,107,107,252,107,252,252,252,107,252,107,107,106,106,106,106,106,106,106,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,16,17,16,17,16,16,16,17,110,109,110,109,110,109,110,252,110,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,110,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,107,252,252,252,252,252,252,252,109,109,109,109,109,109,107,109,252,109,252,252,252,252,252,252,252,252,252,252,107,252,107,252,107,252,252,109,109,109,109,109,109,109,252,109,107,107,252,252,252,109,252,252,252,107,107,107,107,107,252,252,252,107,252,107,107,106,106,106,106,106,106,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,110,109,110,109,110,109,110,109,110,109,110,252,109,109,109,252,109,109,252,252,252,109,252,252,252,252,252,252,252,110,252,109,252,109,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,252,109,108,109,252,252,252,252,252,252,252,107,252,252,252,252,252,252,252,252,109,109,252,109,109,109,252,109,252,109,252,109,252,107,252,109,252,252,252,109,252,107,252,107,252,107,252,107,109,109,109,107,107,106,106,106,106,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,16,16,17,16,109,110,109,110,109,110,252,110,252,110,252,110,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,108,109,109,109,252,109,252,252,252,252,252,252,107,252,252,252,107,252,107,252,107,109,109,109,109,109,109,109,109,109,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,107,107,107,107,107,109,107,109,107,109,109,107,106,107,106,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,252,110,110,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,109,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,107,252,252,252,252,109,252,109,108,109,252,252,252,252,107,252,252,252,107,252,252,252,109,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,107,107,107,109,107,109,107,109,107,109,109,107,106,107,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,109,110,109,110,109,110,252,110,252,110,252,110,252,110,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,252,107,252,107,109,107,109,109,109,109,109,109,109,109,109,252,109,109,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,109,109,109,109,109,106,107,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,109,110,109,110,109,110,109,110,109,110,109,110,252,110,109,110,252,110,110,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,108,109,252,109,252,109,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,252,252,252,109,109,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,252,109,109,109,109,109,109,109,109,109,109,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,110,109,110,109,110,109,110,252,110,252,110,252,110,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,109,109,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,252,109,109,109,109,109,109,109,109,109,109,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,109,109,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,252,252,252,252,252,252,110,252,110,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,108,109,252,109,252,109,252,109,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,109,109,109,109,109,109,109,109,109,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,109,110,109,110,109,110,252,110,252,110,252,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,108,252,252,252,252,252,252,252,252,252,109,109,108,109,252,109,109,109,252,252,252,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,109,109,109,252,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,109,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,109,110,109,110,109,110,109,110,109,110,252,110,109,110,252,252,109,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,252,109,252,109,252,109,252,109,252,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,252,252,109,109,109,109,109,109,109,109,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,110,109,110,109,110,109,110,109,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,108,109,109,109,109,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,109,109,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,15,16,16,16,16,16,16,16,110,109,110,109,110,109,110,109,110,109,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,110,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,252,109,109,109,109,109,109,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,110,109,110,109,110,252,252,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,252,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,109,109,252,109,109,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,16,15,16,16,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,109,109,109,109,109,109,109,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,109,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,110,109,110,109,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,109,252,109,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,109,109,109,109,109,109,109,109,109,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,110,109,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,108,109,252,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,108,108,109,109,109,109,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,109,110,109,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,109,252,109,252,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,109,108,109,108,109,109,109,109,109,109,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,109,110,109,110,109,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,109,109,109,109,109,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,252,252,252,252,252,252,252,252,252,107,107,107,107,107,109,109,109,109,109,109,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,109,110,109,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,109,109,109,252,109,252,109,252,252,252,252,252,252,252,108,107,107,109,107,109,107,109,109,109,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,15,16,110,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,252,109,252,252,252,252,252,252,252,108,108,107,107,107,109,109,109,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,110,109,110,109,110,109,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,109,252,252,252,252,252,109,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,108,108,108,109,107,109,107,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,16,15,15,15,109,110,109,110,109,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,109 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,109,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,252,252,252,252,252,252,108,108,108,108,108,109,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,109,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,252,109,252,109,252,252,252,252,252,252,107,107,109,107,109,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,110,109,110,109,110,109,110,252,110,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,108,109,109,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,252,252,252,252,252,108,108,107,107,107,107,107,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,110,109,110,109,252,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,109,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,252,109,252,109,252,108,252,108,252,107,109,107,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,15,15,15,14,15,15,15,15,109,110,109,110,252,110,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,252,109,252,252,252,107,107,107,107,107,107,107,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,109,110,109,110,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,252,109,252,109,252,107,107,107,252,107,252,107,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,14,15,15,15,14,15,14,15,110,109,110,109,109,252,109,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,109,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,252,107,107,107,107,107,107,107,252,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,110,109,252,252,252,252,252,252,252,252,252,252,252,252,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,107,107,107,107,107,107,107,252,106,107,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,109,110,252,109,252,109,252,252,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,109,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,107,107,107,107,107,107,107,107,106,107,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,252,252,109,109,109,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,252,107,252,107,252,106,107,106,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,110,110,109,109,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,109,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,107,107,106,107,107,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,15,15,15,14,110,110,109,109,109,109,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,109,107,252,107,252,107,106,106,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,15,252,110,109,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,109,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,107,107,107,107,107,107,107,107,106,106,107,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,110,109,110,109,109,109,109,252,110,252,109,110,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,252,109,107,107,107,107,109,107,107,109,252,106,107,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,109,110,252,110,252,109,252,109,109,110,252,110,110,110,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,108,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,109,109,109,107,107,107,107,107,107,109,107,109,106,106,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,15,14,14,14,14,110,109,110,109,110,109,109,252,252,109,109,109,110,110,110,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,109,107,107,109,107,107,107,109,107,109,107,106,106,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,252,110,109,110,252,109,252,109,252,109,109,110,109,110,110,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,109,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,109,109,109,109,107,107,107,107,107,107,107,107,107,106,106,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,110,110,109,110,109,110,109,252,252,109,109,109,110,110,110,110,252,109,109,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,109,109,107,107,107,107,107,109,107,109,107,109,106,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,110,109,110,252,110,252,252,252,109,252,109,109,110,110,110,252,109,109,109,252,109,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,109,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,109,109,109,109,107,107,107,107,107,107,107,107,107,107,106,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,110,110,109,110,109,252,252,252,252,109,109,109,109,110,110,109,252,109,109,109,109,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,107,109,109,109,107,107,107,109,107,107,107,109,107,106,106,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,14,14,15,14,15,14,15,14,110,110,252,110,252,110,252,109,252,109,252,109,109,109,109,110,252,109,252,109,252,109,109,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,109,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,109,109,109,109,109,107,107,107,107,107,107,107,107,107,109,106,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,110,109,110,109,110,109,252,252,252,252,109,109,109,109,110,110,110,252,109,109,109,109,109,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,107,109,109,109,109,107,107,109,107,107,107,109,107,109,107,106,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,14,14,14,14,15,14,14,14,110,110,252,110,252,110,252,109,252,109,252,109,252,109,110,110,252,109,252,109,109,109,109,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,109,109,109,109,109,107,107,107,107,107,107,107,109,106,106,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,110,109,110,109,110,252,252,252,109,252,109,109,109,109,110,252,110,252,109,109,109,109,109,109,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,107,109,109,109,109,109,109,107,107,107,107,109,107,109,106,106,106,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,110,110,252,110,252,110,252,252,252,109,252,109,252,109,109,110,252,110,252,109,109,109,252,109,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,109,109,109,109,109,109,107,107,107,107,107,107,107,106,106,106,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,110,109,110,109,110,109,110,252,252,252,109,252,109,109,109,110,110,109,110,109,109,109,109,109,109 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,107,109,107,109,109,109,109,109,107,107,107,109,107,109,106,107,106,106,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,110,252,110,252,110,252,110,252,252,252,109,252,109,252,109,109,110,110,110,252,110,252,109,109,109,109 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,109,109,109,109,109,109,109,109,107,107,107,107,107,106,106,106,106,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,110,110,109,110,109,110,252,110,109,252,252,109,252,109,109,109,109,110,252,110,109,110,109,109,109,109 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,108,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,107,109,107,109,109,109,109,109,109,109,107,109,107,107,106,107,106,106,106,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,110,109,110,252,110,252,110,252,252,252,109,109,109,252,109,252,109,110,110,252,110,252,110,252,109,109 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,109,108,109,109,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,109,109,109,109,109,109,109,109,109,109,107,107,107,106,106,106,106,106,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,110,109,110,109,110,109,110,109,252,109,109,109,109,252,252,252,109,109,109,252,110,252,252,109,252,109,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,107,109,107,109,109,109,109,109,109,109,109,109,107,107,106,107,106,107,106,106,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,109,110,109,110,109,110,252,110,252,109,252,109,109,110,109,252,252,109,109,252,252,252,252,252,109,252,109 +,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,109,109,109,109,109,109,109,109,109,109,109,109,107,107,106,106,106,106,106,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,14,14,13,14,110,109,110,109,110,109,110,109,252,109,109,109,109,110,110,109,110,110,252,252,252,252,252,252,252,109,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,109,107,109,107,109,107,109,109,109,109,109,109,109,109,109,109,106,106,106,106,106,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,109,110,109,110,252,110,109,252,252,109,252,109,109,110,110,252,252,252,252,252,252,252,252,252,252,252,109 +,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,108,108,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,109,109,109,109,109,109,109,109,109,109,109,109,109,109,107,106,106,106,106,106,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,13,14,14,14,13,14,13,14,110,109,110,109,110,109,252,109,252,109,109,109,109,110,110,110,252,252,252,252,252,109,252,252,252,109,252 +,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,108,252,108,252,108,252,252,252,252,252,108,252,108,252,108,252,252,252,252,107,107,252,107,109,107,109,107,109,107,109,109,109,109,109,109,107,107,109,109,109,107,106,106,106,106,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,110,109,110,109,110,252,109,252,109,252,109,109,109,110,252,252,252,252,252,252,252,252,252,252,252,109 +,252,252,252,252,252,252,252,252,252,252,109,252,108,252,108,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,108,252,108,252,108,108,108,108,108,252,108,108,108,252,252,252,107,252,252,107,107,107,107,107,107,109,109,109,109,109,109,109,109,107,107,107,107,109,107,107,107,106,106,106,106,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,110,109,110,109,252,109,252,109,252,109,110,110,252,252,252,252,252,252,252,109,252,109,252,109,252 +,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,108,108,252,108,252,108,252,108,108,108,252,108,108,108,252,107,252,107,252,107,252,107,107,107,107,107,109,107,109,107,109,107,109,109,109,109,107,107,109,107,109,107,109,107,109,106,106,106,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,110,252,110,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,252,252,108,108,108,108,108,108,108,108,107,107,252,107,252,107,252,107,107,107,107,107,107,107,109,107,109,109,109,109,109,109,109,107,107,107,109,107,107,107,107,106,106,106,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,13,14,13,13,13,14,13,14,110,109,110,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252 +,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,108,108,108,108,108,252,108,252,108,252,107,252,107,252,107,252,107,252,107,252,107,109,107,109,107,109,107,109,107,109,109,109,107,109,107,109,107,109,107,109,107,106,106,106,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109 +,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,108,108,108,108,108,108,108,108,108,107,107,252,107,107,107,252,107,252,107,252,252,107,107,107,107,107,107,109,109,109,109,109,109,107,107,109,107,107,107,107,107,106,106,106,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,109,110,109,110,109,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252 +,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,252,108,108,108,252,107,252,107,252,107,252,107,252,107,252,107,252,107,107,107,109,107,109,107,109,107,109,109,109,109,109,107,109,107,107,107,106,106,106,106,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,109,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109 +,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,109,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,108,108,108,108,108,108,107,107,107,107,107,252,107,252,107,252,107,252,107,252,109,109,109,109,109,107,107,109,109,109,109,109,109,107,107,107,107,107,106,106,106,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,110,109,110,109,110,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252 +,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,108,108,108,108,252,108,252,108,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,109,107,109,107,109,107,109,107,109,109,109,109,109,109,109,106,109,106,106,106,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,13,14,110,109,110,252,110,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,109,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,252,109,252,108,108,108,108,108,108,108,108,108,107,107,107,107,252,107,107,107,252,107,252,107,252,252,252,109,109,109,109,109,109,109,109,109,109,109,109,109,108,106,108,106,106,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,109,110,109,110,252,110,252,252,252,252,252,252,252,252,252,252,109,252,252,252 +,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,109,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,252,108,252,252,108,108,108,108,108,108,252,108,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,109,107,109,107,109,109,109,107,109,109,109,109,107,106,107,106,106,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,14,13,13,13,109,110,109,110,252,110,252,252,252,252,252,252,252,252,252,252,109,252,252 +,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,109,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,108,108,252,252,252,108,108,108,108,108,108,108,108,107,107,107,107,107,252,107,252,107,252,107,252,252,252,109,109,109,109,109,109,109,109,109,109,109,109,107,107,107,107,106,106,106,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,109,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,109,108,252,108,252,108,252,252,108,108,108,108,252,108,252,108,252,107,252,107,252,107,252,107,252,107,252,107,252,107,109,107,109,107,109,109,109,109,109,109,107,107,107,107,107,106,107,106,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,110,109,110,252,110,252,252,252,252,252,252,252,252,252,252,109,252,252 +,252,252,252,252,108,252,109,252,252,252,252,252,109,252,109,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,108,108,109,108,252,252,252,108,108,108,108,108,108,108,107,107,252,107,107,107,252,107,252,107,252,252,109,107,109,109,109,109,109,109,109,109,109,109,109,107,107,107,107,107,106,106,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,109,110,109,110,109,110,252,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,108,108,252,108,252,108,252,109,252,252,108,108,252,108,108,108,252,107,252,107,252,107,252,107,252,107,252,107,109,107,109,107,109,107,109,109,109,109,109,109,107,107,107,107,107,107,106,106,106,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,109,110,252,110,252,110,252,252,252,252,252,252,252,252,252,252,252 +,252,252,252,252,108,252,252,252,252,252,252,252,109,252,109,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,252,108,109,109,252,252,252,108,108,108,108,108,107,107,107,107,107,107,252,107,109,107,109,107,109,109,109,109,109,109,109,109,109,109,109,109,109,109,107,107,107,107,107,106,106,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,110,109,110,252,110,252,110,252,252,252,252,252,252,109,252,252,252 +,252,252,252,108,252,252,252,252,252,252,252,109,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,108,108,252,108,252,108,109,108,252,109,252,252,108,108,108,107,252,107,252,107,252,107,252,107,109,107,109,107,109,107,109,107,109,107,109,109,109,109,109,109,109,109,107,107,107,106,107,106,106,106,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,110,109,110,252,110,252,110,252,252,252,252,252,252,252,252,252 +,252,252,108,252,252,252,252,252,252,252,252,252,109,252,108,252,108,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,108,108,108,109,109,109,109,252,252,252,108,108,108,107,107,107,107,107,107,252,107,107,107,109,109,109,107,109,109,109,109,109,109,109,109,109,109,109,109,109,107,107,106,107,106,106,106,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,110,109,110,252,110,252,110,252,252,252,252,252,252,252,252 +,252,252,252,108,252,252,252,252,252,252,252,109,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,108,108,252,108,109,108,252,108,252,252,252,252,108,108,252,107,107,107,252,107,252,107,109,107,109,107,109,107,109,107,109,107,109,109,109,107,109,109,109,109,109,107,107,106,107,106,106,106,106,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,110,252,110,252,110,252,110,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,109,108,108,109,109,109,109,252,252,252,252,252,108,108,108,107,107,107,107,107,107,107,107,109,107,109,107,109,109,109,109,109,109,109,109,109,109,109,109,109,107,107,106,107,106,106,106,106,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,13,13,12,13,13,13,13,13,109,252,110,252,110,252,252,252,252,252,252,252,252 +,252,252,252,108,252,252,252,252,252,252,252,109,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,109,252,252,252,108,252,108,252,109,252,252,252,252,108,108,108,107,252,107,252,107,109,107,109,107,109,107,109,107,109,107,109,107,109,109,109,109,109,109,109,107,107,106,107,106,107,106,106,106,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,109,252,110,252,110,252,109,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,108,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,108,252,108,109,108,109,252,109,109,108,252,252,252,252,252,252,252,108,108,108,107,107,107,107,107,107,109,107,109,107,109,109,109,107,109,109,109,109,109,109,109,109,109,107,107,106,107,106,107,106,106,106,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,13,13,12,13,109,252,110,252,252,252,252,252,252,252,252 +,252,252,252,108,252,252,252,252,252,252,252,109,252,252,252,108,252,252,252,252,252,252,109,252,252,252,109,252,252,252,252,252,252,108,252,108,252,109,109,252,109,252,108,252,108,252,108,252,252,252,252,252,108,252,107,107,107,109,107,109,107,109,107,109,107,109,107,109,107,109,107,109,109,109,109,106,107,109,106,107,106,107,106,106,106,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,252,110,252,110,252,110,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,109,252,252,109,108,252,109,252,252,252,252,252,252,252,252,108,108,107,107,107,107,107,107,107,107,109,107,109,107,109,109,109,109,109,109,109,107,109,107,107,106,107,106,107,106,106,106,106,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,252,110,252,252,252,252,252,252,252,252 +,252,252,252,108,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,109,109,252,252,252,109,252,108,252,108,252,252,252,252,252,252,252,108,108,107,252,107,109,107,109,107,109,107,109,107,109,107,109,107,109,109,109,107,109,107,107,106,107,106,107,106,106,106,106,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,252,110,252,109,252,109,252,252,109 +,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,108,109,252,252,252,252,252,252,252,252,252,252,252,252,108,107,107,107,107,107,107,107,109,107,109,107,106,107,106,107,109,107,109,107,109,107,109,107,107,106,107,106,106,106,106,106,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,110,252,252,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,109,109,109,252,109,252,109,252,108,252,252,252,108,252,252,252,252,252,107,107,107,107,107,109,107,109,107,107,107,107,107,109,107,109,107,109,107,109,107,109,107,107,106,107,106,106,106,106,106,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,109,110,252,110,252,252,252,109,252 +,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,109,109,107,109,107,107,107,107,107,106,107,109,107,109,107,109,107,107,109,107,106,107,106,106,106,106,106,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,109,110,252,252,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,252,109,252,109,252,109,252,109,252,109,252,107,252,252,252,252,252,252,107,107,252,107,109,109,109,107,107,107,109,107,109,107,109,107,109,107,109,107,107,107,107,106,107,106,106,106,106,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,252,110,252,109,252,252,252 +,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,108,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,107,107,107,109,109,109,107,107,107,107,107,107,107,109,107,109,107,109,107,106,106,107,107,107,106,106,106,106,106,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,252,110,252,252,252,252 +,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,107,107,252,107,109,109,107,107,107,107,109,107,109,107,109,107,109,107,107,106,107,107,107,107,107,106,106,106,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,12,12,13,12,252,110,252,109,252 +,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,108,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,109,109,109,107,107,107,107,107,109,107,109,107,109,107,106,106,107,107,107,107,107,106,106,106,106,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,110,252,252,252,252 +,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,107,252,107,109,107,109,109,107,107,109,107,109,107,109,107,109,107,107,106,107,106,107,107,107,107,106,106,106,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,214,214,201,201,216,12,12,12,12,12,12,12,12,12,12,110,252,252,252 +,252,252,108,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,108,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,107,107,107,109,109,109,107,107,107,109,107,109,107,109,107,106,106,107,106,107,106,107,107,107,106,106,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,202,202,202,214,201,201,216,216,216,216,216,216,216,12,12,12,12,12,252,252,252 +,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,108,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,107,107,107,252,107,107,107,109,107,109,107,109,107,109,107,109,107,109,107,109,106,107,106,107,106,107,107,107,107,106,106,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,202,202,202,202,203,214,201,201,201,216,216,216,216,216,216,216,216,216,12,252,110,252 +,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,109,107,107,107,109,107,106,107,109,107,109,107,109,107,109,106,107,106,107,107,107,107,107,106,107,106,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,202,202,202,202,202,203,202,202,214,214,201,201,216,216,216,216,216,216,216,216,216,216,252,252 +,252,108,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,107,252,107,109,107,107,107,109,107,106,107,109,107,109,107,109,107,109,106,107,106,107,106,107,106,107,107,107,106,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,202,202,202,202,202,203,202,202,202,203,202,214,201,201,216,216,216,216,216,216,216,216,216,216,252 +,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,108,109,108,109,108,109,252,252,252,109,252,252,252,252,252,252,252,252,252,107,252,107,109,109,109,109,109,107,106,107,106,107,109,107,109,107,109,106,107,106,107,106,107,107,107,107,107,106,106,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,202,202,202,202,202,203,202,202,202,203,202,203,203,214,201,216,216,216,216,216,216,216,216,216,216,252 +,252,108,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,108,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,107,252,107,109,107,109,109,106,107,109,107,109,107,109,107,109,106,107,106,107,106,107,107,107,107,107,106,106,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,202,202,202,202,202,202,203,202,202,202,203,202,203,203,203,214,201,201,216,201,216,216,216,216,216,216,216,216 +,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,108,252,252,252,108,109,108,109,108,109,108,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,107,252,109,109,109,109,109,106,107,106,107,109,107,109,107,109,106,106,106,107,106,107,107,107,107,106,106,106,106,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,202,202,202,202,203,203,203,203,202,202,202,202,203,202,203,202,214,201,201,216,214,201,216,201,216,216,216,216,216 +,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,108,252,252,252,252,252,108,109,108,109,108,109,252,109,252,109,252,109,252,109,252,252,252,252,252,107,252,252,252,109,109,107,109,109,109,107,109,107,109,107,109,107,107,106,107,106,107,106,107,107,107,107,106,106,106,106,106,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,202,202,202,202,203,203,202,202,203,202,202,202,202,203,203,203,203,202,202,214,201,216,214,214,201,216,201,216,216,216,216 +,108,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,108,252,252,252,252,252,252,252,108,109,108,109,109,109,109,109,252,252,252,252,252,252,252,252,252,252,107,107,106,107,109,107,109,106,106,106,106,107,109,107,109,106,106,106,107,106,107,106,107,107,107,107,106,106,106,106,106,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,12,12,12,12,12,12,12,11,202,203,203,203,202,202,202,202,203,203,203,202,202,202,203,203,203,202,202,202,214,201,214,214,214,214,201,216,201,216,216,216 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,109,108,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,107,107,107,109,107,109,107,107,106,107,107,109,107,109,106,106,106,107,106,107,106,107,107,107,107,107,106,106,106,106,106,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,202,202,202,203,202,202,202,203,202,203,202,203,202,202,202,203,202,203,202,203,202,203,214,201,214,204,203,214,201,201,216,201,216,216 +,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,108,252,252,252,252,252,252,252,108,109,109,109,109,109,252,109,252,252,252,252,252,252,252,252,107,107,252,107,109,107,109,107,109,106,107,106,107,106,107,107,107,107,107,106,106,106,107,107,107,106,107,106,106,106,106,106,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,203,202,203,203,202,202,202,202,202,202,203,203,202,202,202,202,203,202,203,203,202,202,203,202,203,214,214,203,204,204,214,201,201,216,201,216 +,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,108,252,252,252,252,252,252,252,252,252,109,109,252,109,252,109,252,109,252,252,252,252,252,252,107,107,252,107,109,107,109,107,109,107,107,106,107,106,107,106,107,106,107,106,107,106,107,106,107,106,107,106,106,106,106,106,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,203,202,203,202,202,202,202,202,203,202,203,202,203,202,202,204,203,202,203,202,203,203,203,202,203,202,203,202,214,203,204,203,204,214,201,216,201,216,201 +,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,252,109,252,109,252,252,252,252,252,252,107,107,107,107,107,107,109,107,109,107,109,106,106,106,107,107,107,106,107,107,107,107,106,107,107,106,107,106,106,106,106,106,106,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,12,11,12,12,202,202,203,202,202,202,202,202,202,202,203,202,203,202,203,203,202,202,202,202,203,202,203,203,203,202,202,202,202,202,203,203,203,203,204,204,214,201,201,216,201,216 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,252,109,252,252,252,252,252,107,107,107,109,107,109,107,109,107,109,107,107,106,107,106,107,106,107,106,107,106,107,107,107,107,107,106,107,106,106,106,106,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,203,202,202,202,203,202,203,202,203,202,203,202,203,202,203,202,203,203,202,202,202,202,203,202,203,203,203,203,202,202,203,202,203,202,203,203,204,203,204,214,201,201,201,216,201 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,108,252,252,109,109,109,252,252,252,252,252,252,252,107,252,107,107,107,107,107,109,107,109,107,109,106,107,106,107,106,107,107,107,107,107,107,107,107,107,106,107,106,106,106,106,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,202,202,202,202,202,202,202,202,202,203,202,203,202,203,203,203,203,203,203,202,202,202,202,202,202,203,203,203,204,204,202,202,202,203,203,203,203,204,204,204,204,204,214,214,201,201,216 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,252,109,252,252,252,252,252,107,107,107,109,107,109,107,109,107,109,107,107,106,107,106,107,106,107,106,107,107,107,107,107,106,107,106,106,106,106,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,202,203,202,203,202,202,202,202,202,203,202,203,202,203,202,203,202,203,203,202,202,202,214,214,214,201,202,203,203,203,214,214,214,202,202,203,202,203,203,204,203,204,203,204,204,214,214,214,201,201 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,252,252,252,252,252,252,252,252,107,107,107,107,107,109,107,109,107,109,107,107,107,107,107,107,107,107,106,107,106,107,106,107,106,106,106,106,106,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,202,202,202,202,202,202,202,202,202,202,202,202,203,203,203,203,203,203,202,202,202,202,203,214,214,214,214,214,203,203,214,201,201,201,214,202,202,202,203,203,203,204,203,203,204,204,204,204,214,214,201,201 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,108,252,252,109,252,109,252,252,252,252,252,252,252,107,107,107,109,107,109,107,109,107,109,107,107,106,107,107,107,106,107,106,107,106,107,106,107,106,106,106,106,106,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,202,202,203,202,202,202,203,202,203,202,203,202,203,202,203,202,202,202,203,202,202,202,203,202,204,203,204,203,204,203,204,214,214,201,216,201,214,202,203,202,203,204,204,203,204,203,204,204,204,204,214,214,201 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,109,252,252,252,252,252,252,109,252,252,107,107,107,109,107,109,107,109,107,109,107,107,107,107,106,107,106,107,106,107,106,107,106,107,106,106,106,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,202,202,202,202,202,202,202,202,202,202,202,202,203,202,202,202,202,202,202,202,202,202,203,203,203,204,204,203,204,204,204,202,214,201,214,216,201,214,202,202,203,204,204,204,203,203,204,204,204,204,204,214,214,214 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,107,107,107,109,107,109,107,109,107,109,107,107,106,107,106,107,106,107,106,107,106,107,106,107,106,106,106,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,12,11,202,202,203,202,202,202,202,202,203,202,203,202,203,202,202,202,203,202,203,202,203,202,203,202,203,203,204,204,204,203,204,202,203,202,214,214,201,216,201,202,204,203,204,203,204,203,204,203,204,203,204,204,204,214,214 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,252,252,107,106,107,106,107,109,107,109,107,107,106,107,106,107,106,107,106,106,106,107,106,107,106,106,106,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,202,202,202,202,202,202,202,202,202,202,202,202,203,202,202,202,203,203,203,202,203,203,202,202,203,203,203,203,204,204,204,203,202,202,203,203,214,214,214,201,214,203,203,203,204,204,203,203,204,204,204,204,204,204,204,214 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,252,109,252,107,106,107,252,107,109,107,109,107,109,106,107,106,107,106,107,106,107,106,107,106,106,106,107,106,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,11,12,11,11,202,203,202,202,202,203,202,202,202,203,202,203,202,203,202,202,203,204,202,203,202,202,202,203,203,204,203,204,204,204,203,202,202,203,202,203,203,214,214,214,201,214,203,204,203,204,204,203,204,204,203,204,203,204,204,214 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,107,109,109,252,109,106,107,106,107,109,107,109,107,109,106,107,106,107,106,107,106,106,106,106,106,107,107,107,106,106,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,202,202,202,202,202,202,202,202,202,202,202,202,202,202,203,203,204,204,202,202,202,202,203,203,203,203,204,204,204,203,203,202,202,202,203,203,203,203,203,214,214,201,214,203,203,204,204,204,204,204,204,204,204,204,204,204 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,109,107,252,107,252,107,252,107,252,107,109,107,109,106,107,106,107,106,107,106,106,106,107,106,107,106,107,106,106,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,202,202,202,202,203,202,202,202,203,202,202,202,203,202,203,203,204,204,202,202,202,202,203,203,204,203,204,204,204,203,204,202,203,202,203,202,203,203,203,203,204,203,214,214,214,203,204,204,204,204,204,203,204,203,204,204,204 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,109,109,109,109,252,252,252,107,106,107,109,107,109,107,107,106,107,106,107,106,106,106,106,106,107,107,107,106,106,106,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,202,202,202,202,202,202,202,202,202,202,202,202,202,203,203,202,202,204,204,203,202,202,203,203,203,204,204,204,204,203,203,202,202,203,202,203,203,203,203,203,203,204,204,204,214,214,203,204,204,204,203,204,204,204,201,201,201 +,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,252,107,252,107,252,107,252,107,106,107,252,107,109,107,107,106,107,106,107,106,106,106,107,106,107,106,107,106,106,106,106,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,12,11,11,11,11,202,202,202,203,202,203,202,203,202,202,202,202,202,203,202,202,202,203,203,204,204,203,202,203,203,204,204,204,203,204,202,202,202,203,202,203,202,203,203,203,203,204,203,204,203,204,204,204,204,204,214,214,201,201,201,201,216,216 +,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,109,107,109,107,109,109,109,109,252,252,106,107,252,107,109,106,107,106,107,106,107,106,106,106,106,106,107,107,106,106,106,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,202,202,202,202,202,202,202,202,202,202,202,202,202,202,203,202,203,203,203,203,204,203,202,202,203,203,204,204,204,202,202,202,202,202,203,202,203,203,203,203,203,203,204,203,204,204,204,204,203,214,201,201,201,216,216,216,216,216 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,252,107,109,107,252,107,252,107,252,109,252,107,252,107,252,106,107,107,107,106,107,106,106,106,107,106,107,106,106,106,106,106,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,202,202,203,202,202,202,203,202,202,202,203,202,202,202,203,202,203,202,203,203,204,204,204,203,204,203,202,204,204,204,202,202,202,202,203,202,203,202,203,203,203,204,204,203,204,204,204,203,202,214,201,201,201,216,201,216,216,216,216 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,107,107,109,107,109,107,109,109,109,109,252,109,252,109,106,107,106,106,107,107,107,107,107,106,106,106,107,106,107,107,106,106,106,106,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,202,202,202,202,202,202,202,202,202,202,202,202,202,202,204,202,202,202,202,203,203,204,204,204,202,204,204,204,204,204,204,204,202,202,202,202,202,203,202,203,203,203,203,204,204,204,204,204,204,204,214,214,214,214,201,201,216,201,216,216,216 +,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,109,107,252,107,109,107,252,107,252,109,252,109,252,107,252,106,107,106,107,106,107,106,107,106,107,106,107,106,106,106,106,106,106,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,202,202,202,203,202,203,202,203,202,203,202,203,202,202,202,204,202,202,202,203,202,203,203,204,202,204,203,204,203,204,204,204,204,202,202,203,202,203,202,204,203,203,203,204,203,204,204,204,203,204,203,202,202,203,214,214,201,201,216,201,216,216 +,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,109,107,109,107,252,109,109,109,109,109,109,109,252,252,106,106,106,106,107,106,107,107,107,107,107,107,106,107,107,106,106,106,106,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,202,202,202,202,202,202,202,202,203,202,202,202,202,202,203,204,202,202,203,203,203,203,204,204,202,203,204,204,204,204,204,204,204,202,202,202,203,202,203,204,203,203,203,203,204,204,204,204,204,203,202,202,203,203,203,203,214,201,201,216,201,216 +,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,108,108,108,108,108,252,107,109,107,252,107,252,107,109,107,109,107,252,107,252,109,252,109,107,106,107,106,107,106,107,106,107,107,107,106,107,106,106,106,106,106,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,202,202,202,203,202,203,202,203,202,202,202,202,202,202,203,204,202,203,202,203,203,204,203,204,202,203,204,204,204,204,204,204,202,202,202,202,202,203,203,204,203,203,203,204,203,204,204,204,203,202,202,203,202,203,203,204,214,201,201,216,216,201 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,108,109,107,107,107,109,107,109,107,109,109,109,109,252,109,252,109,109,106,107,106,107,107,107,107,107,106,107,106,107,106,106,106,106,106,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,202,202,202,202,202,202,203,202,202,202,202,202,202,202,204,204,202,202,203,203,203,203,204,204,202,203,204,204,204,204,204,204,202,202,203,202,203,203,204,204,202,203,203,203,204,204,204,204,203,202,202,202,203,203,203,203,203,214,201,201,201,216 +,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,108,108,108,252,108,107,107,252,107,109,107,252,107,109,107,252,107,252,109,252,107,109,109,252,106,107,107,107,106,107,106,107,106,107,106,106,106,106,106,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,203,202,202,202,203,202,203,202,203,202,202,202,203,202,203,203,204,202,203,202,203,203,204,204,204,202,204,203,204,203,204,204,203,202,202,202,202,202,203,203,204,203,204,203,204,203,204,204,204,202,203,203,204,202,203,203,204,203,214,214,201,201,201 +,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,108,108,108,108,108,107,107,107,109,107,109,107,109,107,109,109,109,109,109,109,109,109,109,109,107,106,107,106,107,106,107,106,107,106,106,106,106,106,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,202,202,202,202,202,203,203,202,202,202,202,202,202,202,203,203,204,203,203,203,203,203,203,204,202,203,204,204,204,204,204,204,202,202,202,202,202,203,202,204,204,203,203,203,203,204,204,204,203,202,202,203,202,203,204,204,204,204,214,214,214,201,201 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,109,107,109,107,252,107,252,107,109,107,252,107,252,107,109,109,252,109,252,109,107,106,107,106,107,106,106,106,106,106,106,106,106,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,202,202,203,202,202,202,203,202,202,202,202,202,203,202,203,203,204,202,203,202,203,203,204,203,202,203,204,203,204,204,204,204,202,202,202,202,202,202,204,202,203,203,204,203,204,204,204,204,204,202,203,202,202,202,203,203,204,204,204,204,214,214,201 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,107,107,107,107,107,107,109,107,109,107,109,109,109,107,109,109,109,109,109,109,109,109,107,106,107,106,106,106,106,106,106,106,106,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,11,11,10,11,202,202,202,202,202,203,203,203,202,202,202,202,202,203,203,204,202,203,203,203,203,203,203,202,203,203,204,204,204,204,204,204,202,202,202,203,202,203,204,203,203,203,203,204,204,204,204,204,203,202,202,203,202,203,203,204,204,204,204,204,204,214,214 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,107,107,107,252,107,109,107,252,107,252,107,252,107,252,107,252,107,109,109,252,109,252,106,107,106,106,106,107,106,106,106,106,106,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,203,202,202,202,203,202,203,202,202,202,202,202,202,202,203,203,204,202,203,203,204,203,202,202,203,203,204,203,204,203,204,204,202,202,203,202,203,203,204,203,203,203,204,203,204,204,204,204,204,202,202,202,202,202,203,203,204,203,204,204,204,204,204 +,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,107,107,107,107,107,107,107,109,107,109,107,109,109,109,109,109,109,109,109,109,106,107,106,106,106,106,106,106,106,106,106,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,202,202,202,202,202,203,203,202,202,202,202,202,202,203,203,204,202,203,203,203,203,204,202,203,203,204,204,204,204,204,204,202,202,202,202,203,203,203,203,204,203,204,203,204,204,204,204,204,202,203,203,204,202,203,203,204,204,204,204,204,204,204,204 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,252,107,109,107,252,107,252,107,252,107,109,107,109,107,109,109,252,109,252,106,107,106,106,106,107,106,106,106,106,106,106,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,202,202,202,202,203,202,203,202,202,202,202,202,203,203,204,204,203,202,203,203,204,202,202,202,204,204,204,203,204,204,204,202,202,202,203,202,203,203,204,203,204,203,204,203,204,203,204,202,203,202,204,203,204,202,204,204,204,203,204,204,204,204,204 +,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,107,107,252,108,108,108,107,107,107,107,109,107,107,107,252,109,109,109,109,109,109,109,109,109,107,106,106,106,106,106,106,106,106,106,106,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,202,202,202,202,202,202,203,203,203,202,202,202,202,202,203,203,204,204,202,202,204,202,203,204,202,204,204,203,204,204,204,204,202,202,202,202,203,203,203,203,203,203,204,204,204,202,202,202,203,203,203,203,204,204,204,203,204,204,204,204,203,204,204,204 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,252,252,108,108,107,109,107,109,107,252,107,252,107,252,107,109,107,252,107,109,109,252,106,106,106,107,106,106,106,106,106,106,106,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,202,203,202,203,202,203,202,203,202,202,202,202,202,203,203,204,203,204,204,202,202,203,203,204,202,204,203,204,203,204,203,204,202,203,202,203,203,203,203,203,203,204,203,204,204,202,202,203,202,203,203,204,203,204,204,204,204,204,203,204,204,204,204,204 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,107,252,252,252,252,109,108,107,107,107,107,107,107,109,107,252,107,109,109,109,109,109,109,109,109,106,106,106,106,106,106,106,106,106,106,106,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,202,202,202,202,202,202,203,203,202,202,202,202,202,202,204,203,203,203,202,202,203,203,204,203,202,203,204,204,204,204,204,204,202,202,203,203,203,203,203,203,204,203,204,204,204,202,202,202,203,203,203,203,204,204,204,204,204,204,204,204,203,204,204,204 +,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,108,108,252,107,252,252,109,109,107,108,107,107,252,107,252,107,252,107,252,107,109,107,109,109,252,109,107,106,106,106,106,106,106,106,106,106,106,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,202,202,202,203,202,203,203,203,202,202,202,203,202,203,202,203,203,202,202,203,203,204,204,204,202,204,203,204,203,204,204,202,202,203,202,203,203,204,203,204,203,204,204,204,202,203,202,202,202,204,204,204,203,204,204,204,203,204,203,204,204,204,204,204 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,107,252,252,109,109,252,252,107,107,107,107,109,107,107,107,252,109,109,109,109,109,109,109,107,106,106,106,106,106,106,106,106,106,106,106,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,202,202,202,202,203,203,203,202,202,202,202,202,202,202,203,203,203,202,202,203,203,204,204,203,204,203,204,203,204,204,202,202,203,202,203,203,203,203,203,203,204,204,204,204,202,202,202,203,203,204,204,204,204,204,204,204,204,204,204,204,203,204,204,204 +,252,252,252,252,252,108,252,252,252,252,252,252,252,252,108,108,108,252,107,109,109,252,109,252,107,252,107,107,107,252,107,252,107,109,107,109,109,252,109,107,106,107,106,106,106,106,106,106,106,106,106,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,202,203,202,203,202,203,203,203,202,202,202,202,202,203,202,203,203,202,202,203,203,204,204,204,203,204,203,204,203,204,203,202,202,203,202,203,203,203,203,204,203,204,203,204,202,202,202,203,203,204,204,204,203,204,204,204,203,204,203,204,204,203,204,204 +,252,252,252,252,108,252,252,252,252,252,252,252,252,252,108,107,108,107,109,109,109,109,252,252,252,107,107,107,107,107,252,107,252,109,109,109,109,109,109,106,106,106,106,106,106,106,106,106,106,106,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,202,202,202,202,203,203,203,202,202,202,202,202,202,202,203,203,204,202,203,203,204,204,203,203,204,203,204,204,204,204,202,202,203,203,203,203,204,203,203,203,204,204,204,204,202,202,203,203,203,204,204,204,204,204,204,204,204,199,199,199,203,204,204,204 +,252,252,252,252,252,252,252,252,252,252,252,252,252,108,107,252,108,109,109,252,109,252,109,252,252,252,107,107,107,252,107,252,107,109,107,109,109,252,109,106,106,106,106,106,106,106,106,106,106,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,11,10,10,10,202,202,202,202,203,202,203,203,203,202,202,202,202,202,203,203,204,203,202,202,203,203,204,203,204,203,204,203,204,203,204,202,203,202,203,203,203,203,204,203,204,203,204,204,204,202,203,203,204,203,204,204,204,203,204,204,199,199,233,233,201,201,201,201,201 +,252,252,252,252,108,252,252,252,252,252,252,252,252,107,108,108,252,109,109,109,252,109,252,252,252,252,107,107,107,107,107,107,252,109,109,109,109,109,109,106,106,106,106,106,106,106,106,106,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,202,202,202,202,202,203,203,203,202,202,202,202,203,203,203,203,203,202,202,203,203,204,204,203,203,204,204,204,204,204,202,202,202,203,203,203,203,204,203,203,203,204,204,204,204,202,203,203,203,204,204,204,204,204,199,199,233,233,233,200,200,200,200,200,200 +,252,252,252,252,252,252,252,252,252,252,252,252,107,252,108,252,108,252,109,252,109,252,109,252,252,107,107,252,107,252,107,252,107,252,107,109,109,252,106,106,106,107,106,106,106,106,106,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,10,10,11,10,10,10,10,10,202,202,202,202,203,202,203,203,203,202,202,202,203,202,203,202,203,202,203,202,204,203,204,203,204,203,204,203,204,202,203,203,203,203,203,203,204,203,204,203,204,204,204,204,204,202,203,203,204,203,204,204,199,199,233,233,200,200,200,200,200,201,201,201,201 +,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,109,109,109,109,252,109,252,252,107,107,107,107,107,107,252,252,109,109,109,109,109,109,107,106,106,106,106,106,106,106,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,202,202,202,202,202,203,203,203,202,202,202,203,203,202,202,203,203,202,202,203,203,204,204,203,203,204,203,204,204,204,202,203,203,203,203,204,204,204,204,204,204,204,204,204,204,203,203,203,203,204,199,199,233,233,233,233,200,200,200,194,194,234,234,234,234 +,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,109,108,252,109,252,109,252,109,252,107,107,107,252,107,252,107,252,107,109,109,252,109,107,106,106,106,106,106,106,106,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,202,202,202,202,203,202,203,202,202,202,202,202,203,203,204,202,204,202,203,203,204,204,204,203,204,203,204,203,204,202,203,203,203,203,204,203,204,203,204,203,204,203,204,204,203,202,203,203,199,199,199,233,233,233,200,200,200,233,234,234,233,201,201,201,201 +,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,109,109,109,109,252,252,252,252,107,107,107,107,252,252,252,252,109,109,109,109,109,106,107,106,106,106,106,106,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,202,202,202,202,202,203,203,202,202,202,202,203,203,203,203,202,204,204,202,203,203,204,204,203,203,204,204,204,204,202,203,203,203,203,203,203,203,204,204,204,204,204,204,204,202,203,199,199,199,233,233,233,233,200,200,200,233,234,234,233,200,200,200,200,233 +,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,109,109,252,109,252,109,252,109,252,107,252,107,252,107,252,107,109,109,252,109,109,106,107,106,107,106,106,106,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,202,202,202,202,203,203,203,202,202,202,202,202,203,202,202,203,204,203,202,202,204,204,204,203,204,203,204,203,202,203,204,203,203,203,204,203,204,203,204,204,204,204,204,199,199,199,234,234,233,233,234,233,200,200,200,233,234,234,233,200,200,233,234,233,233 +,252,252,252,252,252,252,252,252,252,252,252,108,108,108,109,109,109,109,252,109,252,252,252,252,107,107,107,107,109,109,109,109,109,109,109,109,107,106,252,106,106,106,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,202,202,202,202,202,202,203,203,202,202,202,202,203,202,202,202,203,203,204,203,202,204,204,204,204,203,204,203,204,204,203,203,203,203,203,203,204,203,204,204,204,204,199,199,234,234,234,233,233,233,234,233,200,233,233,233,234,233,233,200,200,234,234,234,233,233 +,252,252,252,252,252,252,252,252,252,252,252,108,108,109,108,252,108,252,109,252,109,252,252,252,107,252,107,109,107,109,109,109,109,109,109,252,106,252,106,106,106,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,202,202,202,202,202,203,202,203,202,202,202,202,203,202,202,203,203,204,204,203,203,204,203,204,204,204,203,204,203,203,203,203,203,204,204,204,203,204,203,204,204,199,234,234,234,233,233,234,233,234,233,200,233,234,192,234,233,200,200,200,200,200,233,233,234,234 +,252,252,252,252,252,252,252,252,252,252,108,108,108,108,109,109,252,109,252,109,252,252,252,107,107,107,252,107,109,109,109,109,109,109,109,107,107,106,106,106,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,202,202,202,202,202,202,203,202,202,202,202,202,202,202,203,203,203,203,204,203,203,203,204,204,204,203,204,204,204,203,203,203,203,203,204,203,204,203,204,199,234,234,234,199,234,234,234,234,234,234,234,234,234,234,234,233,200,233,200,200,200,234,233,234,234,234 +,252,252,252,252,252,252,252,252,252,108,108,109,108,252,108,252,109,252,109,252,109,252,109,107,107,252,107,109,109,252,109,107,109,107,107,107,106,107,106,106,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,202,202,202,202,202,203,203,202,202,202,202,202,202,202,202,203,203,204,203,204,203,204,203,204,204,204,203,204,203,203,203,204,203,204,204,204,203,204,199,192,199,192,192,199,192,193,192,192,193,193,234,234,234,234,234,234,234,200,234,233,234,233,234,234,234,233 +,252,252,252,252,252,252,252,252,108,108,108,108,109,108,109,109,252,109,252,252,252,252,107,107,107,107,252,109,109,107,107,106,107,106,107,106,107,106,106,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,10,10,10,10,10,10,10,9,202,202,202,202,203,203,203,202,202,202,202,202,202,202,202,202,203,203,204,204,204,204,204,204,204,203,204,204,204,203,203,203,204,204,204,203,204,199,192,199,192,192,199,199,192,192,193,192,193,193,193,234,200,192,234,234,234,234,234,234,233,234,234,194,234,233 +,252,252,252,252,252,252,252,108,108,109,108,252,108,252,109,252,109,252,109,252,252,252,107,252,107,252,252,109,107,109,106,107,107,107,106,107,106,106,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,202,202,203,202,202,203,202,202,202,202,202,203,202,202,202,203,203,204,203,204,203,204,203,204,203,204,203,204,203,203,203,204,203,204,204,204,203,199,192,192,192,193,199,192,192,193,192,193,193,193,192,234,234,200,233,234,234,234,234,234,234,234,194,234,233,233 +,252,252,252,252,252,252,108,108,108,108,108,108,252,109,252,109,252,252,252,252,252,252,107,107,252,252,252,107,106,106,107,107,107,106,107,106,107,106,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,10,9,10,10,202,202,203,202,203,203,202,202,202,202,202,202,202,202,203,203,203,203,204,204,204,203,204,204,203,203,204,204,204,203,203,203,204,204,204,203,199,192,199,192,192,192,199,192,192,192,193,193,193,192,192,192,234,234,234,234,234,234,234,234,234,194,194,234,233,233 +,252,252,252,252,252,252,108,108,108,252,108,252,109,252,109,252,109,252,109,252,252,252,252,107,107,252,107,106,107,106,107,107,107,107,106,107,106,107,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,202,202,203,202,203,202,203,202,203,202,202,202,203,202,203,202,203,203,204,203,204,203,204,204,204,203,204,203,204,203,203,203,204,203,204,204,204,199,192,192,193,192,192,199,193,192,193,193,193,192,192,192,192,192,192,192,234,192,193,193,234,193,194,194,234,234,233 +,252,252,252,252,252,252,108,108,108,108,109,109,252,109,252,252,252,252,252,252,252,252,252,107,252,107,106,107,106,107,109,109,107,106,107,106,106,106,106,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,202,202,202,203,203,203,203,202,202,202,202,202,202,202,202,203,203,203,203,204,204,204,204,202,203,204,203,204,204,203,203,203,203,204,204,204,199,192,199,192,192,193,199,199,192,193,193,193,193,192,192,192,192,192,192,193,192,193,193,193,193,194,194,194,194,194,234 +,252,252,252,252,252,252,108,252,108,252,108,252,108,252,109,252,252,252,252,252,252,252,109,252,252,106,107,106,107,107,107,252,107,107,106,107,106,106,106,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,202,202,203,202,203,202,203,202,202,202,202,202,202,202,203,202,203,203,204,204,204,203,202,204,204,203,204,203,204,203,204,203,204,203,204,199,192,199,193,192,192,199,193,192,192,192,193,192,193,192,193,192,192,192,193,192,193,192,193,193,194,193,194,194,194,194,194 +,252,252,252,252,252,108,108,108,109,108,109,109,252,252,252,252,252,252,252,252,252,107,107,107,106,109,109,107,106,107,252,109,107,107,107,106,106,106,106,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,202,202,202,203,203,203,202,202,202,202,202,202,202,202,202,203,203,203,204,204,204,202,203,204,203,203,203,204,204,203,203,204,203,204,204,199,192,192,192,199,199,199,192,193,193,193,192,192,192,193,192,192,193,192,192,192,192,192,192,193,193,194,194,194,194,194,194 +,252,252,252,252,252,108,108,109,108,252,108,252,109,252,109,252,252,252,107,107,107,106,106,252,107,109,107,107,107,107,107,252,107,107,106,106,106,106,106,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,202,202,203,202,203,203,202,202,203,202,202,202,202,202,203,203,204,203,204,204,202,202,204,204,204,203,204,203,204,203,203,203,204,203,199,192,199,199,193,199,193,192,193,192,193,192,192,192,193,192,192,192,193,192,193,192,193,193,194,193,194,194,194,194,194,194,194 +,252,252,252,252,252,108,252,108,108,108,109,252,252,252,252,252,108,107,107,107,107,107,252,107,109,109,252,106,107,107,252,252,107,107,106,106,106,106,106,106,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,202,202,202,203,203,203,202,202,202,202,202,202,202,203,203,203,203,204,204,204,202,203,203,204,203,204,203,204,204,203,203,203,203,204,199,192,192,193,192,192,192,193,192,193,193,192,192,192,192,193,192,192,192,192,192,193,193,193,193,194,194,194,194,194,194,194,194 +,252,108,108,252,108,252,108,252,108,109,108,252,109,108,108,252,108,252,107,252,107,252,107,109,107,252,109,107,107,252,107,109,107,107,106,106,106,106,106,106,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,10,9,202,202,203,202,203,203,202,202,202,202,202,202,203,202,203,203,204,203,204,202,203,203,204,204,204,203,204,203,204,203,204,203,204,199,192,192,199,192,193,192,193,192,193,193,193,192,192,192,193,192,193,192,192,192,193,193,194,193,194,193,194,194,194,194,194,194,194 +,108,108,108,108,252,252,108,108,252,108,109,109,252,108,108,108,252,107,107,107,252,252,252,109,109,109,109,106,107,106,252,109,107,107,106,106,106,106,106,106,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,202,202,202,202,203,203,203,202,202,202,202,202,202,204,203,203,203,203,204,204,202,202,203,203,204,203,203,203,204,204,203,203,204,199,192,199,192,192,192,192,193,192,193,194,193,193,192,192,192,192,192,192,193,192,192,192,193,193,194,193,194,194,194,194,194,194,194,194 +,108,252,108,252,252,252,108,108,108,252,108,252,108,252,108,252,108,252,107,109,107,252,107,109,109,252,107,107,106,252,107,109,107,107,106,106,106,106,106,106,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,202,202,202,203,202,203,203,202,202,203,202,202,202,204,202,203,203,204,203,202,202,203,203,204,204,204,203,204,203,204,203,204,203,199,192,192,192,192,192,193,192,193,193,194,193,192,192,193,192,193,192,193,192,193,192,193,193,194,193,194,194,194,194,194,194,194,194,194 +,108,108,252,252,108,108,252,252,109,108,108,108,108,108,108,108,108,107,109,107,109,109,109,109,109,109,252,106,107,106,252,109,107,106,106,106,106,106,106,106,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,202,202,203,203,203,202,202,202,202,202,202,202,202,204,203,203,203,203,204,202,202,203,203,204,204,203,204,203,204,204,203,203,199,192,199,192,192,192,193,194,193,193,193,193,194,192,192,192,192,193,193,192,192,192,193,193,193,193,194,194,194,194,194,194,194,194,194,194 +,108,252,108,252,108,252,108,109,109,108,108,252,108,252,108,252,108,109,107,252,107,109,107,252,107,252,109,107,106,252,107,252,106,107,106,106,106,106,106,106,106,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,9,9,9,10,202,202,202,203,203,202,202,203,202,203,202,203,202,203,204,204,203,204,202,203,202,203,203,204,204,204,203,204,203,204,203,204,199,192,192,192,192,193,193,194,193,194,194,194,192,192,192,192,192,193,192,193,192,193,192,193,193,194,193,194,194,194,194,194,194,194,194,194 +,108,108,252,108,252,108,252,109,109,108,108,108,108,108,108,108,252,107,109,107,252,109,109,109,252,109,252,107,107,106,252,106,107,106,107,106,106,106,106,106,106,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,202,202,203,203,203,202,202,203,202,202,202,202,202,203,204,203,204,204,202,202,203,203,204,204,203,203,203,203,204,204,203,199,192,199,192,192,193,193,193,193,193,193,194,194,194,192,192,192,192,192,193,193,192,192,193,193,193,193,194,194,194,194,194,194,194,193,194,194 +,252,108,108,252,108,252,108,252,109,108,108,108,108,252,108,252,108,109,107,252,107,109,107,109,109,252,109,107,106,107,106,107,106,107,106,106,106,106,106,106,106,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,9,9,9,9,9,10,9,9,202,203,203,202,202,202,202,203,202,203,202,202,202,203,204,203,203,204,202,203,203,204,203,204,203,204,203,204,203,204,203,199,192,192,192,192,192,193,192,193,193,194,193,194,194,192,192,192,192,193,192,192,192,193,192,193,193,194,193,194,194,194,193,194,194,194,194,194 +,252,108,108,108,252,108,252,252,109,109,108,108,108,108,108,108,109,107,109,109,252,109,109,109,109,109,252,107,107,106,107,106,107,106,107,106,106,106,106,106,106,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,202,203,202,202,202,202,202,202,203,202,202,202,202,203,204,204,203,203,202,202,203,203,204,204,203,203,204,203,204,204,203,199,192,192,192,192,192,192,193,193,193,193,194,194,192,192,192,192,192,192,193,192,192,192,193,193,193,194,194,194,194,194,194,193,194,194,194,194 +,252,108,108,252,108,252,108,252,252,109,108,108,108,252,108,252,108,109,107,252,107,109,107,252,109,252,109,252,106,107,106,107,106,107,106,107,106,106,106,106,106,106,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,202,202,203,202,203,202,202,202,203,203,202,202,203,202,203,203,204,203,202,202,203,203,204,203,204,203,204,203,204,203,204,203,199,192,193,193,194,193,194,192,193,193,194,193,194,192,193,192,193,192,193,192,192,192,193,192,193,193,194,193,194,193,194,194,193,194,194,194,194 +,252,108,108,108,252,252,252,252,252,252,109,108,108,108,108,108,109,107,107,107,252,109,109,109,252,109,252,109,107,252,252,109,107,106,107,106,106,106,106,106,106,106,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,202,203,203,202,202,202,202,202,203,202,204,202,202,203,203,204,204,204,202,202,202,203,203,204,204,204,203,204,203,204,204,199,192,192,192,193,193,193,193,194,194,193,193,194,193,192,192,192,192,193,193,192,192,192,192,193,193,193,193,194,194,194,194,194,193,194,193,194,194 +,108,252,108,252,108,252,108,252,252,252,252,109,108,252,108,108,108,252,107,252,107,109,107,252,107,252,107,107,107,252,252,109,109,107,106,107,106,106,106,106,106,106,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,202,202,203,202,202,202,202,202,202,203,204,202,202,202,203,203,204,203,202,202,203,203,204,204,204,203,204,203,204,204,204,199,192,192,193,192,194,193,194,193,194,193,194,194,194,192,192,192,193,192,193,193,192,193,194,192,193,193,194,193,194,193,194,193,194,194,194,194,194 +,108,108,108,108,252,252,252,252,252,252,252,252,109,108,108,108,108,107,107,107,252,107,109,109,109,109,252,107,107,252,252,109,109,109,107,106,107,106,106,106,106,106,106,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,202,202,202,202,202,202,202,202,202,203,204,202,202,203,203,204,204,204,202,203,203,203,203,204,203,204,203,204,204,204,204,199,192,192,192,192,193,192,194,193,194,194,194,194,194,192,192,192,192,193,193,192,192,193,194,194,193,193,193,194,194,194,193,194,194,194,193,194,194 +,108,108,108,252,108,252,108,252,252,252,108,252,252,109,108,108,108,109,107,252,107,252,107,252,107,252,109,107,107,252,252,109,109,107,109,107,106,107,106,106,106,106,106,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,202,202,202,202,202,203,202,202,202,202,203,204,202,202,202,203,203,204,202,202,202,203,203,204,204,204,203,204,203,204,204,204,199,193,192,193,192,192,193,193,193,193,194,194,194,193,192,193,192,193,192,193,192,193,193,194,193,194,193,194,194,194,193,194,193,194,193,194,194,194 +,108,108,108,108,252,252,252,252,252,108,252,252,252,108,109,109,108,107,107,107,252,107,252,107,109,109,252,109,107,252,109,109,107,107,109,109,107,106,107,106,106,106,106,106,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,202,202,202,202,202,202,203,202,202,202,203,204,202,202,203,203,204,203,203,202,202,203,203,204,204,203,204,204,204,204,204,203,199,192,193,192,192,193,192,193,193,194,193,194,194,193,192,192,192,192,193,193,192,192,193,193,194,194,194,194,194,194,194,194,194,194,194,193,194,194 +,108,252,108,252,108,252,108,252,252,252,108,252,108,252,252,109,109,107,107,107,107,252,107,252,107,252,107,252,107,252,109,109,107,252,107,109,107,107,106,107,106,107,106,106,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,202,202,202,202,203,202,202,202,202,202,202,203,204,202,202,202,204,204,203,202,203,202,203,203,204,203,204,203,204,203,204,203,204,199,192,192,192,192,192,193,193,193,193,194,194,194,193,192,193,192,193,192,193,192,193,192,193,193,194,194,194,194,194,193,194,193,194,193,194,195,194 +,108,108,108,108,252,108,252,252,252,108,252,108,108,252,252,252,109,107,107,107,109,109,252,252,109,109,252,107,107,109,109,109,107,107,109,109,109,109,107,106,107,106,106,106,106,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,9,9,9,9,8,9,9,9,202,202,202,203,202,202,202,202,202,202,202,203,204,202,202,203,203,204,203,202,202,203,203,204,204,204,204,204,204,204,204,203,199,199,192,193,192,192,193,192,193,193,194,194,194,194,192,192,192,192,192,193,193,192,192,193,193,194,194,194,194,194,194,193,193,194,193,194,194,194,194 +,108,108,108,252,108,252,108,252,252,108,108,252,108,252,108,252,252,109,107,252,107,252,107,252,109,252,107,252,107,109,109,109,109,107,107,252,107,109,109,107,106,107,106,106,106,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,202,202,202,202,203,203,202,203,202,202,202,202,204,202,202,203,203,204,202,203,202,203,203,204,204,204,203,204,203,204,204,204,203,199,199,193,192,192,193,193,193,193,194,193,194,194,193,192,192,193,192,193,193,193,192,193,193,194,193,194,194,194,194,194,193,194,193,194,193,194,195,194 +,108,108,108,108,252,252,252,252,252,108,108,108,108,108,252,252,252,252,107,107,252,109,252,252,252,252,107,107,107,107,109,107,109,109,107,107,109,109,109,107,107,106,107,106,106,106,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,9,9,9,8,202,202,202,202,203,202,202,202,203,202,202,202,204,204,202,202,204,204,203,202,203,203,203,203,204,204,204,204,204,204,204,204,204,199,192,192,192,193,192,193,192,193,193,194,193,194,192,192,192,192,193,193,193,193,192,192,193,193,194,194,194,194,194,193,193,194,194,194,194,194,194,194 +,108,252,108,252,108,252,108,252,252,252,108,108,108,252,252,252,252,252,107,107,107,252,107,252,252,107,107,109,107,109,107,109,107,252,107,109,107,109,107,109,109,107,106,107,106,106,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,202,202,203,202,203,203,203,202,203,202,203,202,202,204,204,202,203,203,204,202,202,202,203,203,204,204,204,203,204,204,204,203,204,203,199,192,193,192,192,192,192,193,193,193,193,194,194,192,192,192,193,192,193,192,193,192,193,192,194,193,194,194,194,194,194,193,195,194,194,193,194,195,194 +,108,108,108,108,252,252,252,252,252,252,252,108,108,107,252,252,252,252,107,107,107,107,252,252,252,107,107,107,107,109,109,109,109,109,107,109,107,107,109,109,109,109,107,106,107,106,106,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,202,202,202,202,202,202,203,202,202,202,202,202,202,204,204,202,202,203,203,204,202,202,203,203,204,204,204,204,204,204,204,204,204,204,204,199,192,192,192,193,192,193,193,194,193,194,194,194,192,192,192,192,193,192,193,193,192,192,193,194,194,194,194,194,194,194,194,194,195,194,194,195,195,194 +,108,108,108,252,108,252,108,252,252,252,252,252,108,252,252,252,107,252,107,252,107,252,107,252,107,252,107,107,107,109,107,109,107,109,109,107,109,107,107,109,107,109,109,107,106,107,106,106,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,202,202,202,202,202,203,203,203,202,203,202,202,202,204,204,202,202,202,203,204,202,202,202,203,203,204,203,204,203,204,204,204,204,204,199,199,192,192,192,192,193,193,193,193,194,194,194,194,192,192,192,193,192,193,193,194,193,192,193,194,193,194,193,194,195,195,194,195,194,194,194,195,194,194 +,108,108,108,108,252,252,109,252,252,252,252,252,252,252,108,107,252,252,252,107,107,107,252,107,252,109,109,107,109,109,107,107,109,109,109,109,109,107,107,107,109,109,109,109,109,106,107,106,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,153,154,154,154,154,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,202,202,202,202,202,202,202,203,203,202,202,202,202,203,203,204,202,203,202,204,203,203,202,203,203,204,204,204,204,204,204,204,204,204,203,199,192,192,193,192,193,192,193,193,194,193,194,193,194,194,192,192,192,193,193,193,193,193,193,194,194,194,194,194,194,194,194,194,194,195,194,194,194,195,194 +,252,108,108,252,108,252,108,252,252,252,109,252,252,252,109,252,107,252,252,108,107,109,107,252,107,252,107,252,109,109,107,109,107,252,107,109,109,109,107,107,107,109,107,109,109,107,106,106,106,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,153,153,153,153,153,153,154,154,154,153,154,154,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,202,202,202,202,203,202,203,203,203,202,202,202,203,203,204,204,202,203,203,203,203,203,202,202,203,203,204,203,204,203,204,204,204,204,204,199,192,192,192,193,193,193,193,193,193,193,193,194,194,194,193,192,193,192,193,193,193,193,194,193,194,194,194,194,194,195,194,194,195,193,194,194,195,195,194 +,109,108,108,108,109,108,252,252,252,252,252,252,252,252,252,252,108,107,252,107,108,107,252,107,109,109,109,109,252,109,107,107,109,107,109,109,109,109,109,107,107,109,109,109,109,107,107,106,106,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,153,153,153,153,152,152,152,152,152,153,153,154,153,154,154,154,154,154,154,153,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,202,202,202,202,202,202,203,203,203,203,203,202,203,203,204,204,202,203,204,203,203,203,202,202,203,203,204,204,204,204,204,204,204,204,204,203,199,192,192,193,192,193,192,193,192,194,193,194,193,194,194,192,193,192,193,193,193,193,193,193,194,194,194,194,194,193,194,194,194,194,195,194,195,194,195,194 +,252,108,108,252,108,252,252,252,252,252,109,252,109,252,252,252,107,252,107,108,107,252,107,109,107,252,107,252,109,252,107,109,107,109,107,109,107,109,107,109,107,107,107,109,107,109,107,107,106,106,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,8,9,153,153,152,152,152,157,157,155,156,157,157,152,153,153,153,153,153,153,154,154,154,154,154,154,154,154,8,9,8,9,8,9,8,9,8,9,8,9,202,202,202,202,202,203,202,203,202,203,202,202,202,204,204,202,202,204,204,203,203,204,202,203,203,204,204,204,203,204,204,204,204,204,204,204,199,192,192,192,193,192,193,192,193,194,194,193,194,192,193,194,192,192,192,193,193,194,193,194,193,194,194,194,194,193,194,195,194,195,194,194,195,195,195,194 +,109,252,108,108,252,252,109,252,252,252,252,252,252,252,252,252,108,107,108,252,107,107,107,107,109,109,109,109,252,252,107,107,109,107,109,107,109,109,109,107,107,107,109,109,109,109,109,107,107,106,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,152,157,156,156,155,155,157,157,156,155,156,156,157,152,153,153,152,152,153,153,153,153,153,154,154,154,154,154,154,154,154,8,8,8,8,8,8,8,8,202,202,202,202,203,203,203,202,203,202,204,202,202,202,202,202,203,203,204,204,203,202,202,203,203,204,204,204,204,203,204,204,204,204,204,199,192,192,192,193,192,193,192,193,193,194,193,194,193,192,193,194,192,194,193,193,193,193,193,193,194,194,194,194,194,193,194,194,195,195,195,194,195,195,195,194 +,252,252,108,108,108,252,108,252,252,252,109,252,252,252,252,252,108,252,107,252,107,252,107,109,107,252,107,252,109,252,107,109,107,252,107,109,107,252,107,107,107,109,107,109,107,109,109,107,107,106,106,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,152,157,157,157,156,156,155,157,156,156,155,157,156,157,156,152,153,157,156,152,152,153,153,154,153,153,154,153,154,154,154,154,154,154,154,154,8,9,8,8,202,202,203,204,202,203,202,202,202,203,204,203,202,202,202,203,203,204,203,204,203,204,202,203,203,204,204,204,203,204,203,204,204,204,204,199,192,192,192,192,193,192,192,193,193,194,194,193,192,193,193,194,193,194,192,193,193,194,193,194,193,194,194,194,195,194,194,195,194,195,194,195,194,195,195,195 +,109,252,109,108,108,252,252,252,252,252,252,252,252,252,252,252,108,107,108,109,107,107,107,107,109,107,109,109,252,109,107,107,107,107,109,107,109,107,109,107,107,107,109,107,109,109,109,107,107,106,106,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,157,157,157,157,156,156,155,155,157,157,156,156,155,156,156,156,156,152,157,157,156,156,152,153,153,153,154,154,154,154,153,154,154,154,154,154,154,154,154,154,202,202,203,204,202,202,202,202,202,203,203,204,202,202,202,203,203,203,203,204,204,204,203,203,204,204,204,204,204,204,204,204,204,204,204,204,199,192,192,192,193,192,193,192,193,193,194,194,194,192,193,194,194,193,194,193,193,193,193,194,194,194,193,194,194,195,194,194,194,195,195,195,195,195,195,195,195 +,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,108,107,108,109,252,252,107,107,109,107,252,107,252,107,252,109,252,107,109,107,252,107,252,107,107,107,109,107,109,107,109,109,109,107,107,106,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,9,8,8,8,157,157,157,156,157,155,156,155,157,156,156,155,155,156,157,156,156,155,157,156,157,155,152,153,153,153,153,153,153,154,154,154,154,154,154,154,154,154,154,154,202,202,204,202,202,202,202,202,203,203,204,204,203,202,203,202,203,203,204,203,204,204,203,203,202,204,204,204,204,204,204,203,204,203,204,204,199,192,192,192,192,192,192,193,193,193,193,194,192,192,193,193,194,194,193,194,193,193,194,193,194,193,194,194,195,194,195,195,195,195,195,194,195,195,195,194,192 +,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,107,108,107,109,109,252,107,107,107,109,109,109,109,252,109,252,107,252,107,107,107,109,107,109,107,107,107,107,107,109,109,109,109,107,106,106,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,157,157,157,157,156,156,155,155,157,157,156,156,155,155,157,156,155,157,157,156,156,156,156,152,153,153,153,153,153,153,153,153,153,154,153,154,154,154,154,154,202,202,202,202,202,203,202,202,203,203,204,204,202,202,202,203,203,203,203,204,204,204,203,202,203,204,204,204,204,204,204,204,204,204,204,204,192,192,192,192,193,192,193,192,193,193,194,192,192,193,193,193,193,194,194,194,194,194,194,194,194,193,193,194,194,195,195,195,195,195,195,195,194,195,194,192,199 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,108,107,252,109,252,252,252,107,109,107,252,107,252,109,252,109,107,107,252,107,252,107,252,107,107,107,109,107,109,107,109,107,109,107,107,106,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,8,8,8,8,8,8,9,8,157,157,157,156,156,155,156,155,157,156,156,155,156,155,157,157,157,156,157,156,156,155,156,152,153,153,152,152,152,152,152,152,153,153,153,153,154,153,154,153,202,202,203,202,203,202,202,202,203,203,204,203,204,202,203,202,203,203,204,203,204,204,202,202,204,204,204,203,204,204,204,203,204,204,204,199,192,192,192,192,192,192,192,193,193,193,193,192,193,192,193,193,194,194,194,194,194,193,194,193,194,194,194,193,195,194,195,193,195,194,195,194,194,195,192,199,192 +,109,252,109,252,109,252,252,252,252,252,252,252,252,252,108,107,108,107,252,252,252,107,107,107,107,107,109,109,252,109,252,107,107,107,252,107,252,107,109,107,107,107,107,107,109,107,109,109,107,106,106,106,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,157,157,157,156,156,156,155,155,157,157,156,156,156,155,155,155,157,157,157,156,156,156,202,202,202,152,152,202,202,203,202,202,203,152,152,152,152,153,153,153,154,202,202,202,202,202,202,202,203,203,203,203,204,204,202,202,203,203,203,203,203,203,204,202,203,203,204,204,204,204,204,204,204,204,204,204,199,192,192,192,192,192,192,193,192,193,193,194,192,192,193,193,193,194,194,194,194,193,194,194,194,194,193,193,195,194,195,195,195,195,194,194,195,195,192,199,192,193 +,252,109,252,252,252,252,252,252,252,252,252,252,252,108,107,109,107,252,107,252,109,107,107,252,107,252,107,252,107,252,109,107,109,252,107,252,107,252,107,109,107,107,107,109,107,109,107,109,106,107,106,106,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,157,157,157,157,156,156,155,155,157,157,156,156,155,156,155,155,156,202,202,202,202,202,202,202,202,202,202,202,202,203,202,203,202,203,203,204,152,153,153,154,202,203,202,203,202,202,202,203,202,203,203,204,203,204,202,203,202,203,202,203,203,204,202,203,203,204,204,204,204,204,204,204,204,204,204,204,199,193,192,192,192,192,192,192,193,193,194,192,192,193,192,193,193,194,195,194,194,194,193,194,194,194,195,193,193,195,194,195,195,194,195,195,195,192,199,192,192,192 +,109,252,109,252,252,252,252,252,252,252,252,252,252,107,108,107,109,109,252,109,252,252,107,107,109,107,109,109,252,107,252,109,107,107,107,107,252,107,109,107,109,107,107,107,109,109,109,109,107,106,107,106,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,157,157,157,157,156,156,156,155,157,156,157,156,156,155,202,202,202,202,202,202,202,202,202,202,202,202,202,202,203,203,204,204,203,203,203,204,204,152,153,153,202,202,203,202,202,202,202,202,203,203,203,203,204,204,202,202,202,202,203,203,203,202,203,203,203,203,204,204,204,204,204,204,204,204,204,204,192,192,193,192,192,192,192,193,193,194,192,192,193,193,193,193,194,195,195,195,194,194,194,195,195,195,193,193,195,195,195,195,195,194,194,195,192,199,192,192,193,192 +,252,252,252,252,252,252,252,109,252,252,252,252,252,108,107,109,107,252,107,252,252,252,109,107,107,252,107,107,107,252,107,252,107,252,107,252,107,252,107,109,107,109,107,107,107,109,107,109,106,107,106,106,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,157,157,157,157,156,156,155,155,157,157,156,157,155,156,202,202,202,202,202,202,202,202,203,202,202,203,202,203,203,204,204,203,202,203,203,204,203,204,152,153,202,203,202,202,202,202,202,203,202,203,203,204,203,204,202,203,202,203,203,202,202,203,203,204,203,204,204,204,203,204,204,204,203,204,204,204,192,192,192,192,192,192,193,193,193,192,192,193,192,193,193,194,194,195,195,194,195,195,194,195,193,195,193,195,195,195,195,195,195,194,195,192,199,192,192,192,192,192 +,109,252,109,252,252,252,109,252,252,252,252,252,252,107,108,107,109,107,252,252,252,252,252,252,107,107,107,107,109,252,252,107,107,107,107,107,107,107,252,107,109,107,107,107,109,107,109,109,107,106,107,106,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,7,8,8,8,157,157,157,157,156,156,156,155,155,157,157,156,156,156,155,202,202,202,202,202,202,203,203,202,202,202,202,203,203,204,204,204,203,203,203,203,203,204,204,155,152,203,202,202,202,202,202,202,202,203,203,203,203,204,204,202,202,203,202,202,202,203,203,203,203,204,204,204,204,204,204,204,204,204,204,204,204,192,193,192,193,192,193,192,193,192,192,192,192,193,193,193,194,195,195,195,195,194,195,195,195,195,195,194,195,195,195,195,195,194,195,192,199,192,192,192,192,193,192 +,252,109,252,252,252,252,252,252,252,252,252,252,107,108,107,252,108,252,107,252,109,252,109,252,107,107,107,252,107,252,109,252,107,252,107,252,107,252,107,109,107,109,107,109,107,109,107,109,106,107,106,106,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,157,157,157,157,157,156,156,155,155,156,157,156,156,155,156,202,203,202,203,202,203,202,202,202,203,202,203,203,204,203,204,204,203,203,204,203,204,203,204,155,155,202,202,202,202,202,202,202,203,202,203,203,204,203,204,202,203,202,202,202,203,202,203,203,204,203,204,203,204,204,204,204,204,204,204,204,199,192,193,192,192,192,192,193,192,192,193,192,193,193,194,194,195,194,195,195,194,195,195,195,195,195,195,195,195,194,195,195,195,195,192,199,199,192,193,192,193,192,193 +,252,252,109,252,252,252,109,252,252,252,252,252,108,107,108,107,109,109,252,109,252,252,252,109,252,107,107,107,252,252,252,107,107,107,107,107,252,107,107,107,109,109,107,107,109,109,109,109,107,106,107,106,106,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,7,7,7,8,157,157,157,157,156,156,155,155,157,157,156,156,156,156,202,202,202,202,202,203,202,202,202,203,203,203,203,203,203,204,204,204,203,203,203,204,204,204,204,203,155,202,202,202,202,202,202,202,202,203,203,203,203,204,204,202,202,203,202,202,203,203,203,204,204,204,204,204,204,204,204,204,204,204,204,204,192,199,192,192,192,192,193,192,192,192,192,193,193,193,193,195,195,195,195,194,195,195,195,195,195,195,194,195,194,195,195,195,195,192,199,192,192,192,192,192,192,193,192 +,252,109,252,252,252,109,252,252,252,252,252,252,108,252,107,109,108,252,107,252,109,252,252,252,109,107,107,252,107,252,107,107,107,252,107,252,107,252,107,252,107,252,107,107,107,109,107,109,106,107,106,106,106,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,157,157,157,156,156,155,155,156,157,156,157,156,156,155,202,202,203,202,202,202,203,202,203,203,204,203,204,203,204,203,204,203,204,203,204,203,204,203,202,202,155,202,202,202,202,202,202,202,203,202,203,203,204,204,202,202,203,202,202,202,203,203,204,203,204,203,204,204,204,203,204,204,204,204,204,204,192,192,192,192,192,192,192,193,192,192,192,192,193,192,193,194,195,194,195,195,195,195,195,195,195,195,195,194,195,194,195,195,192,199,192,192,193,192,193,192,193,192,193 +,252,252,109,252,109,252,252,252,252,252,252,252,108,108,108,108,109,109,252,252,252,252,252,109,252,107,107,107,252,252,107,107,107,107,107,107,107,107,252,107,109,109,109,107,107,107,109,109,107,106,107,106,106,106,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,157,157,157,157,156,155,155,156,157,157,157,156,156,155,155,202,202,202,203,202,202,203,204,203,203,203,203,203,204,204,204,204,203,203,203,203,204,204,202,202,202,202,202,202,203,203,202,202,202,202,203,203,204,204,204,202,202,204,202,202,203,203,204,204,204,203,204,204,204,204,204,204,204,204,204,204,204,192,192,192,192,193,192,193,192,192,192,192,192,192,193,194,195,195,195,195,194,195,194,195,195,195,195,194,195,195,195,195,195,199,192,192,192,192,192,192,192,192,193,192 +,252,109,252,252,252,252,252,252,252,252,252,252,108,108,108,252,108,252,109,252,109,252,252,252,109,252,107,252,252,107,107,252,107,252,107,252,107,252,107,109,107,109,107,109,107,109,107,107,106,107,106,106,106,106,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,202,206,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,157,157,157,157,156,156,155,157,156,157,156,157,156,156,155,202,202,203,202,203,202,202,202,204,204,203,203,204,203,204,204,204,203,203,203,204,202,202,202,202,202,202,202,203,202,203,202,202,202,203,203,204,203,204,202,202,203,204,202,204,202,203,203,204,203,204,203,204,203,204,203,204,204,204,204,204,199,192,192,193,192,192,192,192,193,192,192,192,192,193,193,195,195,194,195,194,195,195,195,195,195,195,195,195,194,195,195,195,199,192,192,192,192,192,192,193,192,193,192,193 +,252,252,109,252,109,252,252,252,252,252,252,252,108,108,108,108,252,109,252,109,252,252,252,252,252,252,107,107,252,252,107,107,107,107,107,107,252,107,109,107,109,109,109,109,109,107,109,106,107,106,106,106,106,106,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,202,203,203,206,207,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,157,157,157,157,156,155,157,156,157,157,156,156,156,156,202,202,202,202,202,202,202,202,203,203,204,203,203,203,204,204,204,204,203,203,202,202,202,202,202,202,202,202,203,203,203,203,202,202,203,203,204,204,203,203,202,202,203,203,204,202,203,203,203,203,204,203,204,204,204,204,204,204,204,204,204,204,192,192,192,192,193,192,192,193,192,192,192,193,192,192,193,195,194,194,194,194,194,195,194,195,195,195,195,194,195,195,195,199,199,192,192,192,192,192,192,192,192,192,193,192 +,252,252,252,109,252,252,252,252,252,252,252,252,108,109,108,109,252,252,109,252,109,252,109,252,109,252,107,252,107,252,107,107,107,252,107,252,107,109,107,109,107,252,107,109,109,107,107,107,106,107,106,106,106,106,106,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,202,203,202,203,203,204,206,207,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,7,7,6,7,157,157,157,157,155,157,156,157,157,157,156,156,156,156,202,202,202,202,202,202,202,203,203,204,204,204,203,204,203,204,204,203,202,203,202,203,202,203,202,203,203,203,202,203,203,203,202,202,203,204,202,203,202,203,202,203,203,204,202,203,202,203,202,203,203,204,203,204,203,204,204,204,204,204,204,204,192,192,192,193,192,192,192,192,192,192,192,192,193,193,192,194,194,194,194,194,195,194,194,195,195,195,195,195,195,195,199,199,192,193,192,192,192,193,192,193,192,193,192,193 +,252,252,109,252,109,252,252,252,252,252,252,252,108,108,109,252,109,109,252,252,252,252,252,252,252,252,107,107,252,252,107,107,107,107,107,107,252,107,109,107,109,109,109,109,109,107,109,106,107,106,106,106,106,106,106,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,202,202,203,203,202,202,203,203,206,207,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,157,157,157,157,156,155,156,157,157,157,156,156,156,156,155,202,202,202,202,202,202,203,203,203,204,204,203,204,204,204,204,202,202,202,202,203,202,202,202,203,203,203,203,203,203,203,203,202,202,204,202,202,202,202,202,203,203,204,204,203,202,203,203,203,203,203,203,204,204,204,204,204,204,204,204,204,199,192,192,192,192,192,192,193,192,192,193,192,193,193,194,194,194,194,194,194,192,193,194,195,195,195,195,195,195,195,199,199,192,192,192,192,192,192,192,193,193,193,192,193,193 +,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,252,108,252,109,252,109,252,252,252,109,252,252,107,107,252,109,252,107,252,107,252,107,109,107,252,107,252,107,109,107,107,107,109,106,106,106,106,106,106,106,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,202,203,202,203,202,202,202,203,203,204,206,207,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,157,157,157,157,155,156,157,156,157,156,157,156,156,155,156,202,203,202,203,202,203,202,203,203,204,204,204,203,204,203,202,202,203,202,203,202,203,202,203,203,203,202,203,203,203,202,202,202,203,203,204,203,204,202,203,202,204,203,204,202,203,202,203,203,204,203,204,203,204,203,204,204,204,204,204,204,199,192,192,192,192,192,193,192,192,192,192,193,193,193,193,194,194,194,194,192,194,194,195,195,195,194,195,195,195,199,199,192,192,192,192,192,193,192,193,192,193,192,193,192,193 +,252,252,109,252,109,252,252,252,252,252,252,252,108,108,108,108,252,109,252,109,252,252,252,252,252,252,252,107,107,107,109,109,107,107,107,107,109,107,109,107,109,109,109,109,107,107,107,109,107,106,106,106,106,106,106,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,202,202,202,202,202,202,203,202,204,202,202,203,203,206,207,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,6,7,6,7,6,7,6,6,157,157,157,157,157,157,156,155,156,157,156,156,156,156,202,202,202,202,202,202,202,203,203,203,204,204,202,203,203,202,202,202,202,203,202,203,202,203,203,203,203,204,204,204,202,202,202,203,203,203,203,204,202,203,203,203,203,204,202,202,202,203,203,203,203,203,203,203,199,199,204,204,204,204,204,204,192,192,192,192,192,193,193,193,193,192,193,192,193,193,194,193,194,194,192,193,194,195,195,195,195,195,195,195,199,192,192,192,192,192,192,192,192,193,192,193,192,193,193,193,193 +,252,109,252,252,252,252,252,252,252,252,252,252,107,252,108,252,252,252,109,252,109,252,109,252,252,252,109,107,107,252,107,252,107,252,107,252,107,109,107,109,107,252,107,107,107,109,107,109,106,106,106,106,106,106,106,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,202,202,202,202,203,203,204,202,204,202,203,203,204,206,207,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,7,6,157,157,157,156,156,155,155,157,157,156,157,156,156,155,202,202,202,202,203,202,203,203,204,203,204,202,203,202,202,202,203,202,203,202,203,202,203,203,203,203,204,204,204,202,203,202,203,202,203,203,204,202,203,203,204,203,204,202,203,202,203,202,203,202,203,203,199,199,192,193,204,203,204,204,192,199,192,192,193,192,192,192,193,193,194,192,192,193,193,194,194,194,192,192,193,192,194,193,195,195,195,195,195,195,199,192,192,192,192,192,193,192,193,192,193,192,193,192,193,192,193 +,252,252,109,252,109,252,252,252,252,252,252,252,108,108,109,252,109,109,252,252,252,252,252,252,252,252,252,107,107,107,109,109,252,107,252,107,107,107,109,107,109,109,109,107,107,107,107,109,107,106,106,106,106,106,106,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,202,202,202,202,203,203,204,204,202,204,202,202,203,203,206,207,207,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,157,157,157,156,156,156,155,155,157,157,157,156,156,155,155,202,202,202,202,202,203,203,203,203,204,204,202,202,202,202,203,203,203,203,203,203,203,203,203,203,204,204,202,202,202,202,203,203,203,203,204,204,202,202,203,203,204,204,202,202,203,202,203,203,203,199,199,193,192,194,194,204,204,204,199,199,199,192,193,193,192,192,193,193,193,193,192,193,192,194,193,194,192,192,193,193,193,193,195,195,195,195,195,194,195,199,192,192,193,192,192,192,192,192,192,192,193,193,193,193,193,193 +,252,109,252,252,252,252,252,252,252,252,252,109,107,109,108,252,108,252,109,252,109,252,252,252,252,252,252,107,107,109,107,252,109,252,107,109,107,109,107,252,107,252,107,252,107,109,107,107,106,106,106,106,106,106,106,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,202,203,202,202,202,203,203,204,202,204,202,203,203,204,206,207,207,207,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,6,7,6,6,157,157,157,157,156,156,155,155,156,157,156,156,155,156,155,202,202,203,202,203,202,203,203,204,203,204,202,202,202,203,202,203,203,203,202,203,203,203,204,204,204,204,202,202,202,203,202,203,203,204,203,204,202,202,202,203,203,204,199,199,199,203,202,199,199,192,192,193,193,194,194,194,193,199,199,193,193,194,193,192,192,193,192,193,193,194,192,192,193,193,194,192,192,193,192,193,194,195,194,195,194,195,195,195,195,199,199,192,192,192,192,193,192,192,192,193,193,194,193,193,193,193 +,109,252,109,252,252,252,252,252,252,252,252,252,108,108,108,108,252,109,252,109,252,252,252,252,252,252,252,107,107,107,107,107,252,109,107,107,109,107,109,107,109,109,107,107,109,109,107,106,107,106,106,106,106,106,106,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,202,202,202,202,202,203,203,204,203,202,202,203,204,203,206,207,207,207,206,207,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,157,157,157,156,156,155,156,155,157,156,156,156,156,155,202,202,202,202,202,202,203,203,203,204,204,204,203,203,203,203,203,203,204,203,204,204,204,204,204,204,204,202,202,202,202,202,203,203,203,203,204,204,202,202,203,203,204,199,199,192,193,192,192,192,192,192,192,193,194,193,194,194,192,192,193,193,193,193,194,192,192,192,193,193,193,193,192,193,194,192,192,192,192,192,193,194,194,195,195,195,195,195,195,195,199,199,192,199,192,192,192,192,192,192,193,192,193,193,193,192,193,193 +,252,252,252,252,252,252,252,252,252,252,252,252,107,252,108,252,252,252,109,252,109,252,109,252,252,252,109,107,107,109,107,109,107,252,109,109,107,252,107,109,107,252,106,107,107,107,106,107,106,106,106,106,106,106,106,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,202,202,203,202,203,202,203,202,203,204,204,203,202,202,203,204,204,206,207,207,207,207,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,145,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,5,6,6,6,157,157,156,157,155,156,155,155,156,157,156,156,155,156,202,203,202,202,202,203,202,203,203,204,204,202,202,203,202,203,203,204,203,204,204,204,203,204,204,204,204,202,202,203,202,203,203,204,203,204,204,204,202,202,202,204,204,199,192,193,192,193,193,194,194,192,192,193,193,194,194,192,193,194,192,193,193,194,193,192,192,193,193,194,193,194,192,194,193,192,192,193,192,193,193,194,194,195,195,195,194,195,195,195,199,192,199,193,192,192,192,193,192,193,192,193,193,194,193,193,193,193 +,109,252,109,252,252,252,252,252,252,252,252,252,108,107,109,252,109,109,252,109,252,252,252,252,252,252,252,107,107,107,109,107,109,109,109,107,109,107,109,107,109,109,106,107,107,106,107,106,107,106,106,106,106,106,106,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,202,202,202,202,202,203,202,203,204,202,203,204,204,202,202,203,204,204,206,207,206,207,207,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,145,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,157,157,157,156,156,156,155,155,157,157,156,156,156,156,155,202,202,202,202,203,203,203,203,204,204,202,202,202,202,203,203,203,203,204,204,204,204,204,204,204,204,202,202,203,203,203,203,203,203,204,204,202,202,203,202,203,204,199,199,192,192,193,193,193,193,194,194,192,192,193,193,192,193,194,194,193,193,193,193,194,192,192,192,193,193,194,194,192,193,193,192,192,192,193,193,194,194,193,194,194,194,195,195,195,195,199,192,199,192,193,192,192,192,192,192,192,193,193,193,193,193,194,193 +,252,109,252,252,252,252,252,252,252,252,252,252,107,109,108,252,108,252,109,252,109,252,109,252,252,252,252,107,107,107,107,252,107,252,109,109,107,109,107,252,107,252,107,107,106,107,106,107,106,107,106,106,106,106,106,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,202,202,203,202,202,202,203,202,203,203,204,202,204,204,203,202,203,204,204,206,207,206,207,207,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,145,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,157,157,157,156,156,155,156,155,157,156,157,156,156,155,156,202,202,202,203,202,203,203,204,204,202,202,204,202,203,203,204,203,204,203,204,204,204,204,204,203,204,202,203,202,203,203,204,203,204,204,203,202,203,202,203,202,204,199,193,192,193,192,193,193,193,192,194,193,194,193,192,192,193,193,195,195,193,193,194,193,192,192,193,192,194,193,194,194,193,192,192,192,193,193,194,194,193,194,195,194,195,195,195,195,195,199,192,192,193,192,192,192,192,192,192,193,194,193,194,193,194,193,193 +,109,252,109,252,252,252,252,252,252,252,252,252,108,107,108,108,252,109,252,109,252,252,252,252,252,252,252,107,107,107,107,107,109,109,109,107,109,107,109,107,109,109,107,107,107,106,107,106,107,106,106,106,106,106,106,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,202,202,202,202,203,202,202,203,204,202,204,203,204,202,204,202,202,203,204,206,207,205,206,206,207,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,145,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,5,6,5,6,6,6,5,6,157,157,156,157,156,156,155,155,157,156,156,156,156,156,202,202,202,202,202,203,203,204,204,202,203,203,204,203,203,203,203,203,203,204,204,204,204,204,204,204,204,202,202,203,203,203,203,204,204,204,202,203,203,203,203,203,199,199,192,192,192,193,193,193,193,192,193,194,194,192,192,193,193,194,193,195,195,193,193,194,192,192,192,193,193,193,194,194,192,193,192,192,192,192,193,193,193,194,194,195,195,195,195,195,195,199,192,192,192,193,193,192,192,192,192,193,194,194,193,193,193,193,194 +,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,109,252,252,109,252,109,252,109,252,252,252,108,107,107,252,107,107,107,252,107,109,107,109,107,109,107,252,107,107,106,107,106,107,106,107,106,106,106,106,106,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,202,203,202,203,202,203,202,203,204,202,202,203,203,204,204,202,204,203,204,206,207,205,205,207,207,207,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,145,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,157,157,157,156,156,155,156,155,157,156,156,156,156,155,202,202,203,202,203,203,204,202,202,202,203,203,204,202,203,203,204,203,204,203,204,204,204,204,204,204,204,202,203,202,203,203,204,203,204,202,203,202,203,202,203,203,199,192,192,192,193,192,193,192,193,193,194,194,192,192,193,192,194,194,194,195,195,193,194,192,192,192,193,193,194,193,194,192,193,192,192,192,193,192,193,193,194,193,195,194,195,195,195,194,195,192,192,192,193,192,193,193,192,192,193,193,194,193,194,193,194,193,192 +,252,252,109,252,109,252,252,252,252,252,252,252,109,108,108,252,109,109,252,109,252,109,252,252,252,252,108,107,107,107,107,107,109,107,109,109,107,107,109,107,109,109,109,107,106,106,107,106,107,106,107,106,106,106,106,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,202,202,202,202,202,203,204,203,202,204,202,203,202,203,203,204,202,204,203,204,206,207,205,206,206,207,207,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,145,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,157,157,157,157,156,156,156,155,155,157,157,156,156,155,155,202,202,202,202,204,203,202,202,202,203,203,204,204,203,203,204,204,204,204,203,204,204,204,204,204,204,204,202,202,203,203,204,204,204,202,202,202,203,203,203,203,199,199,192,192,192,192,192,192,193,193,194,194,192,192,193,194,194,193,194,193,195,195,195,192,193,192,192,193,193,193,194,194,194,192,192,192,192,192,193,193,193,193,194,195,195,195,195,195,194,199,192,192,192,192,193,193,193,192,192,193,193,193,194,194,194,193,193,192 +,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,252,252,252,109,252,109,252,109,252,252,252,108,107,107,107,107,252,107,109,109,109,107,109,107,252,107,252,107,107,106,106,106,107,106,107,106,106,106,106,106,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,108,252,108,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,202,202,203,202,202,203,204,203,204,204,202,202,204,203,204,202,203,203,204,204,206,207,205,205,207,207,207,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,145,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,157,157,157,157,156,156,155,156,155,157,156,156,155,156,202,203,202,204,204,203,202,202,202,203,202,203,203,204,204,204,203,204,204,203,203,204,203,204,204,204,204,155,155,203,202,204,203,204,202,202,202,203,202,203,203,204,199,192,192,193,192,192,192,193,193,194,193,192,192,193,192,194,192,194,194,195,193,194,194,193,192,192,192,193,193,194,193,194,193,192,192,193,192,193,192,193,193,194,193,194,194,195,194,195,195,199,192,192,192,193,192,193,193,192,192,193,193,194,193,194,193,193,192,192 +,252,252,252,252,109,252,109,252,252,252,252,252,109,108,108,108,252,109,109,109,252,252,252,252,252,252,108,107,107,107,107,107,252,109,109,109,109,107,109,107,109,109,109,106,107,106,106,106,107,106,107,106,107,106,106,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,108,108,108,108,109,109,109,107,109,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,202,202,202,202,202,204,204,204,203,202,202,203,204,204,204,202,202,203,203,204,206,207,205,206,206,207,207,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,150,144,144,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,157,157,157,157,157,156,157,156,156,155,155,157,156,156,202,202,202,202,203,203,204,203,202,202,202,202,203,203,203,204,204,203,204,204,204,204,204,204,204,204,204,155,155,155,155,202,203,203,204,202,202,202,203,203,203,203,203,199,199,192,192,192,192,192,193,193,194,194,192,192,193,193,194,194,194,194,195,192,193,193,193,193,194,193,192,192,193,194,194,194,192,192,192,193,193,194,194,193,194,194,194,194,195,195,195,195,195,199,192,192,193,193,193,193,193,192,192,192,193,193,194,194,193,192,192,192 +,252,252,252,109,252,252,252,252,252,252,252,252,252,109,108,109,252,252,109,252,109,252,109,252,252,252,108,107,107,252,107,107,107,109,107,109,107,109,107,109,107,252,107,106,107,107,106,106,106,107,106,107,106,107,106,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,108,252,108,252,108,109,109,109,107,109,107,109,107,109,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,202,202,202,202,203,203,204,204,204,202,203,203,204,203,204,202,203,202,204,204,205,206,205,206,207,206,207,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,150,144,144,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,157,157,157,155,156,157,157,157,156,156,155,155,157,203,202,202,202,203,202,203,203,204,204,203,202,202,202,203,203,204,203,204,204,204,203,204,203,204,203,204,204,204,204,156,155,155,155,202,203,204,202,202,202,203,202,203,203,204,203,199,192,192,192,193,192,193,193,194,193,192,192,193,192,193,192,194,194,194,194,192,192,193,193,193,194,194,192,193,193,194,193,194,192,192,192,193,193,194,193,194,194,194,193,194,195,195,195,195,195,199,192,192,192,193,192,193,192,193,192,193,193,194,194,192,192,192,192,192 +,252,252,252,252,109,252,252,252,252,252,252,252,252,107,108,252,109,109,109,109,252,109,252,252,252,252,108,107,107,107,107,107,107,107,109,109,109,107,109,109,109,109,106,107,107,106,107,106,106,106,107,106,107,106,106,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,108,108,108,252,108,252,109,109,109,107,107,109,107,109,107,109,109,107,107,107,107,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,202,202,202,202,203,203,204,204,204,202,203,203,204,204,202,202,203,203,204,204,205,205,206,205,206,207,207,207,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,150,150,144,146,144,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,157,157,157,157,157,156,156,155,155,157,157,156,156,155,157,202,202,202,202,202,203,203,204,204,204,202,202,202,203,203,203,203,204,204,204,204,204,203,203,204,204,204,204,204,204,155,155,155,155,202,202,202,202,202,202,202,203,203,203,203,199,199,192,192,192,192,193,193,193,193,194,192,192,192,194,194,194,194,194,194,192,192,193,193,193,193,195,194,192,192,194,193,193,193,192,192,192,192,193,193,194,194,194,193,194,194,195,195,195,195,195,199,199,192,193,193,193,193,192,192,193,193,193,194,194,192,192,193,192,193 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,252,252,109,252,109,252,109,252,109,252,108,252,107,107,107,107,107,109,109,109,107,109,107,109,107,252,107,107,107,107,107,107,106,107,106,107,106,107,106,106,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,108,108,252,252,252,108,252,252,109,107,109,107,109,107,109,107,109,107,109,107,109,107,107,107,107,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,202,202,202,202,202,203,203,204,203,204,203,204,204,202,202,203,203,204,203,204,204,205,206,205,206,207,206,207,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,150,150,149,146,144,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,157,156,157,157,157,157,157,156,157,155,156,155,155,156,156,155,155,157,202,202,203,202,203,203,204,203,204,204,202,202,203,202,203,203,204,203,204,204,204,203,204,203,204,204,204,203,204,204,156,155,155,202,203,202,202,202,203,202,203,203,204,203,204,199,192,192,193,192,193,192,193,193,192,192,193,192,193,192,194,194,193,194,192,192,193,193,193,194,195,193,194,192,192,194,193,193,192,192,193,192,193,192,193,193,194,193,194,193,194,194,195,195,195,195,199,192,199,192,193,193,194,192,193,192,193,193,194,192,193,192,193,193,193 +,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,109,252,252,108,252,107,107,107,107,252,109,109,107,109,107,109,107,109,106,106,107,107,107,107,107,107,106,106,106,107,106,107,106,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,108,108,252,108,252,252,252,252,109,109,107,107,107,107,107,107,107,109,107,107,107,109,107,107,107,107,107,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,202,202,203,202,203,203,204,204,203,203,204,203,204,202,203,203,203,203,204,204,205,205,207,205,206,207,206,207,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,150,150,150,149,146,147,144,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,5,5,4,5,157,157,156,157,156,156,157,157,157,156,156,156,155,155,155,157,156,156,155,202,202,202,202,203,203,203,203,204,204,204,202,202,202,203,203,203,203,203,203,204,204,204,204,204,204,204,204,204,204,204,155,155,155,202,202,202,202,202,202,203,203,203,203,204,199,199,192,192,192,192,192,193,193,192,192,193,193,193,193,195,195,194,194,192,192,193,193,193,194,194,193,195,194,192,192,193,193,192,192,193,193,193,193,193,193,194,194,194,193,193,194,195,195,195,195,195,199,192,192,193,193,193,193,192,192,193,193,194,194,192,192,193,193,194,192 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,252,252,109,252,109,252,109,252,252,252,108,252,107,107,107,107,107,109,109,109,107,109,107,109,106,106,107,107,107,107,107,107,106,107,106,106,106,107,106,106,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,108,108,252,252,252,252,252,252,252,109,252,109,109,107,109,107,109,107,109,107,109,107,109,107,107,107,107,107,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,202,202,202,202,202,204,204,204,203,204,204,204,204,203,203,204,203,204,203,204,204,205,206,205,205,206,206,207,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,150,150,150,150,149,146,147,144,144,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,157,157,157,156,157,156,156,156,157,157,157,156,156,156,156,155,155,156,156,155,155,202,202,202,203,202,203,203,204,203,204,204,202,203,203,202,203,203,204,203,204,204,204,203,204,203,204,204,204,204,204,155,156,155,155,202,202,202,203,202,203,202,203,203,204,203,199,192,192,192,193,192,193,193,194,192,193,192,193,193,195,195,194,194,192,192,193,193,193,193,194,195,195,195,194,192,193,192,193,192,193,193,194,193,194,194,194,193,193,193,194,193,195,194,195,194,195,195,199,192,192,192,193,193,194,192,193,192,193,193,192,192,194,193,193,193,192 +,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,107,109,109,109,109,109,109,252,252,252,252,108,252,107,107,107,107,107,107,109,107,109,107,109,107,106,107,107,107,107,106,107,106,106,107,107,106,107,106,107,106,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,108,108,252,108,252,252,252,252,252,252,252,109,109,107,109,107,107,107,107,109,107,107,107,109,107,107,107,107,107,107,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,202,202,202,202,202,203,204,204,203,203,204,204,203,204,202,203,203,204,204,204,204,205,205,206,205,205,206,206,207,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,150,148,148,148,146,146,147,147,147,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,5,4,4,4,157,157,157,157,157,156,156,156,157,157,156,155,157,156,156,155,155,155,156,156,155,156,202,202,202,202,203,203,203,203,204,204,204,202,202,203,203,203,203,203,204,204,204,204,204,204,204,204,204,204,204,204,156,155,155,155,202,202,202,202,203,203,203,203,203,203,199,199,192,192,192,192,193,193,193,199,193,194,194,194,195,195,194,194,192,192,194,193,193,193,194,195,195,193,195,195,194,192,193,193,194,192,192,192,193,193,193,193,193,193,193,193,194,195,195,195,195,194,195,199,192,199,193,193,193,192,192,192,193,193,192,192,193,193,193,194,194,192 +,252,252,252,252,252,252,252,109,252,252,252,252,252,252,107,109,107,252,109,252,109,252,109,252,109,252,252,107,107,107,107,252,107,107,107,109,107,109,107,106,107,106,107,252,107,107,106,106,106,107,107,107,106,107,106,106,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,252,108,108,252,252,252,252,252,252,252,252,109,109,109,107,109,109,107,109,107,109,107,109,107,109,107,107,107,107,107,107,107,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,202,202,202,202,203,202,204,204,203,203,204,204,204,204,203,202,204,203,204,204,205,204,205,206,207,205,205,206,207,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,150,150,149,149,149,149,149,144,147,4,5,4,5,4,5,4,5,4,5,4,5,4,5,150,145,145,145,145,145,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,4,5,157,157,157,157,156,157,156,157,156,156,155,157,156,157,155,156,155,155,156,156,155,202,202,202,202,203,202,203,203,204,203,204,204,202,202,203,203,204,203,204,203,204,204,204,204,204,203,204,204,204,204,204,155,156,155,155,202,202,202,203,202,203,202,203,203,204,199,192,192,192,192,193,192,193,199,193,193,194,193,195,194,195,195,192,193,192,193,194,193,194,193,195,195,195,193,195,194,192,194,193,192,193,192,193,192,193,192,193,193,194,193,194,194,195,195,195,195,194,195,199,192,192,192,193,193,192,192,193,193,194,192,193,193,194,193,194,192,192 +,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,107,109,107,109,109,252,109,252,109,252,252,252,107,107,107,107,107,107,107,107,107,109,107,109,106,107,106,107,107,107,107,106,106,107,107,107,107,107,106,107,106,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,108,108,108,252,108,252,252,252,252,252,252,252,252,109,109,109,107,109,109,109,107,109,109,107,107,107,109,107,107,107,107,107,107,107,107,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,202,202,202,203,203,202,204,204,203,203,203,204,204,202,202,203,202,204,204,204,204,205,205,206,205,205,205,206,206,207,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,150,150,150,150,150,150,150,145,144,147,144,144,4,4,4,4,4,4,4,4,4,4,4,4,4,150,149,144,146,147,147,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,157,157,157,157,157,156,157,156,156,155,155,156,156,156,156,155,155,155,156,155,156,202,202,202,202,202,203,203,203,203,204,204,204,202,203,203,204,203,204,203,204,204,204,204,204,204,204,204,204,204,204,204,155,155,155,155,202,202,202,202,203,203,203,203,204,199,199,192,192,192,193,193,193,192,193,193,193,193,195,195,195,195,195,192,192,193,194,194,193,193,195,195,195,195,195,195,194,192,193,192,192,192,193,193,193,193,194,193,194,194,194,194,194,195,195,194,195,194,195,199,192,199,193,193,193,192,193,193,193,193,192,192,193,193,193,192,192,192 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,109,252,109,252,109,252,109,252,109,107,107,252,107,107,107,107,107,109,107,109,106,107,107,109,107,252,107,107,107,107,106,107,106,107,107,107,106,106,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,109,109,109,109,109,109,107,109,107,109,107,109,107,107,107,107,107,107,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,202,202,202,202,202,203,204,204,203,203,204,202,203,204,203,203,202,203,204,204,205,205,213,205,207,205,213,206,214,207,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,150,232,150,232,149,149,232,149,144,232,147,232,144,232,4,4,4,4,4,4,4,4,4,4,4,4,150,148,148,148,148,148,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,157,157,157,157,157,156,157,157,157,156,156,155,157,156,156,155,156,155,155,156,155,202,202,202,203,202,203,203,203,203,204,203,204,204,202,202,203,203,204,203,204,203,204,204,204,203,204,203,204,204,204,204,204,155,155,155,203,202,202,202,203,202,203,203,204,203,199,192,192,192,193,192,193,192,199,192,193,193,194,195,195,194,195,192,192,192,194,193,194,193,195,193,195,193,195,193,195,194,193,193,192,192,193,193,194,194,193,192,193,193,194,193,194,194,195,195,195,194,195,195,199,192,192,192,193,193,192,192,193,192,192,192,193,193,194,192,192,192,192 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,109,109,109,252,109,252,252,252,107,107,107,107,107,107,107,107,107,109,107,106,106,107,107,252,107,252,107,107,107,106,106,107,107,107,107,107,106,106,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,108,108,108,252,108,252,108,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,107,109,109,107,107,107,109,107,109,107,107,107,107,107,107,107,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,202,202,202,202,203,202,203,204,203,203,203,202,203,204,204,204,202,202,204,204,204,204,205,205,206,205,205,205,206,206,206,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,150,150,145,145,145,145,145,145,145,4,4,4,4,150,150,150,150,149,150,149,149,144,144,144,144,147,147,144,144,4,4,4,4,150,145,145,145,145,145,4,4,150,149,146,147,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,157,157,157,157,156,156,157,157,156,156,155,155,156,156,156,156,155,155,155,156,155,202,202,202,202,203,203,203,203,203,203,204,204,204,202,203,203,204,203,204,204,204,204,204,203,204,204,204,204,204,204,204,204,155,155,155,202,202,202,203,203,203,203,203,203,199,199,192,192,192,192,193,193,192,199,193,193,194,195,195,195,195,195,192,192,193,193,194,194,193,193,193,193,195,195,195,195,194,192,193,193,194,193,193,192,192,192,193,193,193,193,194,194,194,194,195,195,195,195,195,199,192,199,193,193,193,192,192,192,193,192,193,193,194,192,192,192,193,193 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,109,252,109,252,109,252,109,252,109,107,107,107,107,252,107,252,107,252,107,107,106,107,107,109,107,252,107,107,107,107,106,107,106,107,107,107,106,106,106,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,108,252,108,108,252,108,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,107,109,109,109,107,109,107,109,107,107,107,107,107,107,107,107,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,202,202,202,202,202,202,202,204,204,203,202,203,203,204,204,204,203,204,203,204,204,205,205,205,205,213,206,205,205,206,206,207,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,150,150,150,149,144,146,146,147,147,4,3,4,150,150,150,150,150,150,145,145,145,146,146,146,146,146,146,147,147,147,3,4,3,150,149,232,146,232,147,4,3,150,149,146,150,150,150,145,145,145,145,145,145,4,3,4,3,4,3,4,3,4,3,4,3,157,157,157,157,156,156,157,156,156,155,155,156,157,156,156,155,156,155,155,156,155,202,203,202,203,202,203,202,203,202,204,203,204,202,203,202,203,204,204,203,204,204,204,203,204,203,204,203,204,204,204,204,204,155,155,155,202,202,203,202,203,203,204,203,204,199,192,192,192,192,193,192,199,199,193,193,194,193,195,194,195,195,193,192,193,193,194,194,195,195,195,193,195,193,195,195,195,195,194,194,193,193,193,192,193,192,193,192,193,193,194,193,194,193,194,194,195,195,195,195,199,192,193,192,193,193,194,192,193,192,192,192,192,192,193,192,193,192,193 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,109,252,109,109,109,252,252,252,107,107,107,107,107,107,107,107,107,107,107,107,106,107,107,109,107,252,107,107,107,107,106,107,107,107,107,107,106,106,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,108,108,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,107,107,109,109,107,109,109,107,107,107,107,107,107,107,107,107,107,107,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,202,202,202,202,203,202,203,203,204,202,203,203,204,202,204,204,204,204,204,204,204,204,205,205,205,205,213,205,213,206,206,206,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,4,4,4,3,150,150,150,149,144,146,146,147,147,4,4,3,150,150,232,149,232,149,232,149,232,144,232,146,232,146,232,147,232,147,150,145,145,145,145,145,145,145,145,3,4,150,149,146,150,149,149,149,144,146,146,147,147,4,4,3,4,4,4,3,4,4,4,3,4,157,157,157,157,156,157,157,157,156,155,155,157,156,156,156,156,155,155,155,155,202,202,202,202,202,203,203,203,202,204,203,204,204,202,202,203,203,204,203,204,204,204,203,204,204,204,204,204,204,204,204,204,155,155,155,155,202,202,202,203,203,203,203,204,199,199,192,192,199,199,199,199,192,193,193,193,193,194,195,195,195,195,192,193,193,193,193,195,195,193,193,195,195,195,195,195,195,195,194,194,193,193,192,192,192,192,192,193,193,193,193,194,194,194,194,195,195,195,195,195,199,192,192,193,193,193,193,192,192,192,192,192,192,192,192,193,192,193,192 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,109,252,109,252,109,252,109,252,109,107,107,107,107,107,107,252,107,252,107,107,106,107,107,109,107,252,107,107,107,107,106,107,106,107,106,107,106,107,106,106,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,108,108,252,108,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,109,252,109,109,109,109,107,107,107,109,107,109,109,109,107,109,107,107,107,107,107,107,107,107,107,107,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,202,203,202,202,202,202,202,203,203,202,202,204,204,204,203,204,203,204,203,204,204,215,205,205,205,215,205,213,205,213,206,214,206,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,149,149,148,148,148,148,148,3,4,3,4,150,150,232,149,232,149,232,149,232,144,232,146,232,146,232,147,232,147,149,144,144,144,149,149,149,149,149,145,145,150,149,146,150,149,149,149,144,146,146,147,147,4,3,4,3,4,3,4,3,4,3,4,157,157,157,157,157,157,156,157,156,156,155,155,156,157,156,156,155,156,155,157,155,203,202,202,202,203,202,203,202,204,203,204,204,204,202,203,203,204,204,204,203,204,204,204,203,204,204,204,203,204,203,204,155,155,155,155,155,202,202,203,203,204,203,204,203,199,199,193,199,192,192,192,192,193,192,193,193,194,193,195,195,195,192,193,193,195,193,195,195,193,192,193,193,195,193,195,195,195,193,194,193,193,192,192,192,192,192,193,193,194,193,194,193,194,194,195,195,195,195,195,199,199,192,199,192,193,193,194,192,193,192,193,192,193,192,193,192,193,193,193 +,108,252,252,252,252,252,252,252,109,252,252,252,252,252,252,107,109,107,109,109,109,109,252,109,252,252,252,107,107,107,107,107,107,107,252,107,107,107,107,107,107,107,252,107,252,107,107,106,106,106,107,106,107,107,107,107,106,106,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,108,252,108,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,107,107,107,107,109,109,109,107,109,107,109,107,107,107,107,107,107,107,107,107,107,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,202,202,202,202,202,202,202,202,203,203,202,203,203,204,203,204,204,204,204,204,204,205,204,205,205,205,205,205,213,205,205,213,206,206,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,3,4,3,4,3,4,3,3,150,150,149,144,146,146,147,148,148,150,150,150,150,150,150,150,150,150,149,149,144,144,144,146,146,146,147,147,147,149,146,146,144,146,144,144,144,149,149,149,150,149,146,232,150,148,148,148,148,148,148,4,3,4,3,3,3,4,3,4,3,4,157,157,157,157,157,157,157,157,157,157,156,156,155,157,156,156,156,156,155,155,157,155,202,202,202,202,202,203,202,203,204,204,204,203,203,202,202,203,204,204,204,204,204,203,203,204,204,204,204,204,204,156,156,155,155,155,155,155,202,202,202,203,203,204,204,199,199,199,199,192,192,193,192,192,192,193,193,193,193,195,195,195,195,192,193,193,193,195,195,193,193,193,193,195,195,195,195,195,195,194,194,193,192,192,192,192,192,192,192,193,193,194,194,194,194,195,195,195,195,195,199,199,192,192,192,192,192,193,193,194,192,192,192,192,192,193,193,193,193,193,193 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,109,252,109,252,109,252,109,252,109,107,107,107,107,252,107,252,107,252,107,107,106,107,107,252,107,252,107,107,107,106,106,107,106,107,106,107,107,107,106,106,106,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,108,108,252,108,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,107,107,109,107,109,107,109,109,109,107,109,107,107,107,107,107,107,107,107,107,107,107,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,202,202,203,202,203,202,202,202,203,203,202,202,204,204,204,203,204,203,204,203,204,204,215,205,215,205,215,205,213,206,215,206,214,206,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,150,150,149,144,146,146,147,144,144,144,144,144,144,144,144,144,144,144,147,149,144,144,144,146,146,146,147,147,147,149,146,232,146,232,146,232,146,232,144,144,150,149,146,147,150,149,149,144,146,146,147,3,4,3,4,3,4,3,4,3,4,157,157,157,157,157,157,157,156,157,157,156,156,155,155,156,157,156,156,155,156,155,157,202,202,202,203,202,203,202,203,204,204,204,203,202,203,202,203,203,204,203,204,204,204,203,204,203,204,204,204,203,157,155,156,155,155,155,155,155,202,202,203,203,204,203,199,199,199,199,193,192,193,192,192,192,193,193,194,193,194,195,195,195,195,192,193,193,195,193,195,195,193,192,193,193,195,193,195,195,195,194,193,192,193,192,193,192,193,192,193,192,193,193,194,195,195,195,195,195,195,199,199,192,193,199,193,192,193,193,194,193,194,194,192,192,193,192,193,192,193,193,193 +,108,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,109,107,109,109,252,109,252,109,252,252,252,107,107,107,107,107,107,107,107,107,107,107,107,106,107,107,252,107,107,107,106,106,106,106,107,106,107,107,107,106,106,106,106,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,108,108,108,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,107,107,107,107,107,107,109,109,109,107,109,107,107,107,107,107,107,107,107,107,107,107,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,202,202,202,202,202,202,202,202,203,202,203,203,204,204,204,203,203,204,204,204,204,205,205,205,205,213,205,205,205,214,206,205,205,214,206,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,150,150,145,145,145,145,145,146,150,150,149,144,146,232,147,144,144,144,144,144,144,144,144,144,144,144,144,147,149,144,144,144,146,146,147,147,147,149,147,147,147,147,147,147,147,147,147,147,150,149,146,147,150,149,149,144,146,232,147,3,3,3,3,3,3,3,3,3,3,157,157,157,157,157,157,157,156,157,156,156,156,155,155,157,156,156,156,156,155,155,156,202,202,202,202,202,202,203,203,204,202,202,202,203,203,202,203,204,203,204,204,203,203,203,203,204,204,204,204,204,156,156,155,155,155,155,155,155,202,203,203,204,204,204,199,199,192,192,192,193,193,192,192,193,193,193,193,194,194,195,195,195,195,192,193,193,195,195,192,192,192,193,193,193,193,195,195,195,194,193,192,192,192,192,192,193,193,192,192,193,193,194,195,195,195,195,195,199,199,192,192,193,193,193,193,193,192,193,193,194,194,192,192,193,192,193,193,193,193,193,193 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,109,252,109,252,109,252,109,252,109,107,107,252,107,107,107,252,107,252,107,107,106,107,107,107,107,107,107,107,106,106,106,107,106,107,107,107,106,107,106,106,106,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,108,108,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,252,107,109,107,252,107,109,107,109,107,109,107,107,107,107,107,107,107,107,107,107,107,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,202,202,202,203,202,203,202,202,202,203,202,203,203,204,204,204,203,204,203,204,203,215,204,215,205,215,205,215,205,213,213,214,206,214,206,206,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,4,3,3,3,150,150,150,149,144,144,146,147,150,150,149,144,146,146,147,144,144,232,144,232,144,232,144,232,144,144,144,144,147,147,144,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,150,150,149,149,144,146,146,147,3,4,3,3,3,4,4,4,4,4,157,157,157,157,157,157,156,156,156,157,156,156,155,155,156,157,156,156,155,156,155,157,202,203,202,202,202,203,203,204,202,202,202,203,203,204,203,204,204,204,204,203,203,204,203,204,203,204,203,204,156,157,155,156,155,155,155,155,202,203,202,203,203,204,199,199,199,193,192,193,192,193,192,193,192,193,193,194,193,194,195,195,195,192,192,193,193,195,195,192,192,193,192,193,193,195,195,195,194,193,192,192,192,193,192,193,192,193,193,192,194,194,193,195,195,195,195,199,199,192,199,193,199,193,192,193,192,193,194,194,192,193,192,193,192,193,192,193,193,194,193,193 +,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,109,109,109,109,109,252,109,252,252,252,107,107,107,107,107,107,107,107,107,107,107,107,106,107,107,252,107,107,107,106,106,107,106,107,107,107,106,107,106,106,106,106,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,108,252,108,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,107,107,107,107,109,109,109,107,109,107,109,107,107,107,107,107,107,107,107,107,107,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,202,202,202,202,203,202,202,202,203,203,202,203,203,204,203,203,204,203,204,204,204,204,205,205,215,205,205,205,213,205,213,213,213,213,214,206,206,206,3,3,215,206,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,150,150,150,149,149,144,146,147,150,150,232,144,146,146,147,144,144,144,144,232,144,232,144,144,144,144,144,144,144,144,147,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,149,232,144,146,152,152,153,153,153,153,153,153,154,153,154,154,157,157,157,157,157,156,156,157,157,156,156,155,155,155,157,156,156,156,156,155,155,202,202,202,202,202,203,203,204,202,202,202,202,202,203,203,204,204,204,204,204,203,204,203,204,204,204,204,204,204,157,156,156,155,155,155,155,155,202,202,203,203,204,199,199,199,192,192,193,192,193,193,192,192,193,193,193,193,194,194,195,194,195,192,192,193,193,193,195,195,192,193,193,193,195,195,195,194,193,192,192,192,192,192,193,193,193,194,194,193,194,195,195,195,195,195,199,192,192,192,193,193,193,193,193,192,193,193,192,192,192,192,193,193,193,193,193,193,193,193,193,193 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,252,109,252,109,252,108,252,107,107,107,252,107,252,107,252,107,107,107,107,107,107,107,107,107,107,106,106,106,107,107,107,106,106,106,106,106,106,106,106,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,108,108,108,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,109,107,107,107,252,109,109,107,109,107,109,107,109,107,107,107,107,107,107,107,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,202,202,202,203,202,204,202,202,202,203,202,203,204,204,203,204,203,204,203,204,204,215,204,215,205,215,205,215,205,215,205,213,206,214,206,206,206,215,205,213,206,214,206,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,148,148,148,148,148,148,148,150,150,149,144,146,146,147,144,144,144,144,144,144,144,144,144,144,144,232,144,144,144,144,147,146,146,232,146,146,146,232,146,146,146,232,146,146,146,146,146,232,146,146,146,146,149,149,152,152,157,156,157,157,156,152,152,153,153,153,153,154,157,157,157,157,157,157,156,157,156,157,156,156,155,157,155,157,156,156,155,156,155,202,202,203,202,203,203,204,204,203,202,202,202,203,203,204,204,204,203,204,204,204,203,204,203,204,203,204,204,204,156,156,155,156,155,155,155,155,202,203,203,204,204,199,199,193,192,193,192,193,192,192,192,193,192,193,193,194,193,194,195,195,192,192,192,193,192,193,193,195,195,193,193,195,195,195,195,194,192,193,192,192,192,193,192,193,194,194,194,194,193,195,195,195,195,199,199,192,192,193,192,193,192,193,192,193,192,192,192,193,192,193,192,193,192,193,193,194,193,194,194,193 +,108,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,252,252,108,252,107,107,107,107,107,107,107,107,107,107,107,106,107,106,107,107,107,106,106,106,107,107,107,106,106,106,107,106,106,106,106,106,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,108,108,108,108,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,107,107,109,107,109,107,109,107,109,107,109,107,107,107,107,107,107,107,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,202,202,202,202,202,204,202,203,202,202,203,203,204,202,203,203,203,203,204,204,204,204,215,205,205,205,213,205,205,205,215,205,205,205,213,205,205,205,213,213,214,206,206,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,3,2,3,3,150,150,149,149,149,149,149,150,150,149,144,146,232,147,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,147,147,147,147,147,147,147,147,147,147,147,146,146,146,232,146,232,146,232,146,146,149,157,157,156,156,157,157,157,156,155,156,155,155,152,152,157,157,157,157,157,157,156,156,157,156,156,156,155,157,156,155,156,156,156,156,155,202,202,202,202,202,202,204,204,203,202,203,203,204,204,204,204,203,203,204,204,204,203,204,204,204,204,204,204,204,204,157,156,156,155,155,155,155,155,203,203,204,204,199,199,192,192,192,192,192,192,193,192,192,192,193,193,193,193,194,194,195,195,192,192,192,192,193,193,193,193,195,195,193,193,195,195,194,194,192,192,192,192,192,192,193,193,194,194,194,195,195,195,195,195,199,199,192,192,193,192,193,193,193,193,192,192,192,192,192,192,193,193,193,193,193,193,193,193,193,193,193,193 +,252,252,108,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,109,109,109,252,109,252,252,252,108,252,107,107,107,107,107,252,107,252,107,107,107,107,106,107,107,107,107,106,106,107,106,107,107,106,106,107,106,106,106,106,106,106,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,108,252,108,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,107,109,252,107,109,107,109,107,109,107,109,107,109,107,107,107,107,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,202,202,202,203,202,203,202,202,202,202,203,204,204,204,203,204,203,204,203,204,203,215,204,215,205,215,205,215,205,215,205,213,205,213,205,215,205,213,205,213,205,214,206,206,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,150,232,149,149,149,149,149,150,150,149,144,146,146,147,144,144,113,114,114,114,114,114,114,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,147,147,146,146,146,146,146,146,146,146,157,157,156,156,155,157,157,157,156,155,156,156,155,156,156,157,157,157,157,157,156,156,157,157,156,156,155,156,157,156,155,157,156,156,155,156,202,202,202,203,202,203,203,202,202,203,203,204,203,204,203,204,203,204,204,204,203,204,203,204,203,204,204,204,204,204,156,157,155,156,155,155,155,155,203,203,203,204,199,199,192,193,192,193,192,193,193,192,192,193,192,193,193,194,194,194,194,195,192,192,192,193,193,195,193,195,193,195,193,195,193,194,194,192,192,193,192,192,192,193,192,194,194,194,194,195,194,195,194,195,199,199,192,193,192,193,192,193,193,193,192,193,192,193,192,193,192,193,192,193,193,194,193,194,193,194,193,194 +,252,252,108,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,109,109,109,109,252,252,252,252,108,252,107,107,107,107,107,107,252,107,107,107,107,107,107,106,107,107,107,106,106,106,107,107,106,106,107,106,107,106,106,106,106,106,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,108,108,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,109,107,109,109,107,109,107,109,107,109,109,109,109,109,107,107,107,107,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,202,202,202,202,202,204,203,202,202,202,203,203,204,203,203,203,204,204,204,204,215,204,215,205,215,205,213,205,215,205,215,205,215,205,215,205,215,205,213,206,215,214,206,206,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,150,150,149,149,149,149,149,150,150,232,144,146,146,147,144,113,113,113,113,113,113,113,114,114,114,114,114,114,114,114,113,113,114,114,114,114,114,144,144,144,144,144,144,144,147,146,146,146,146,146,157,157,157,157,156,156,155,157,157,157,156,155,156,155,155,156,156,157,157,157,157,157,157,156,157,157,156,156,156,155,157,156,156,155,156,156,156,155,202,202,203,203,204,204,203,202,202,203,203,203,204,204,203,203,204,204,204,203,204,203,204,204,204,204,204,204,204,157,157,156,156,155,155,155,155,202,203,203,204,199,199,192,192,192,192,192,193,193,193,192,192,192,193,193,193,193,194,194,195,195,192,192,192,192,193,193,195,195,195,193,195,193,195,194,194,192,192,192,192,193,192,192,193,193,194,194,195,195,195,194,195,195,199,192,192,192,193,192,193,193,193,193,192,192,192,192,192,192,193,192,193,193,193,193,193,193,193,193,193,193 +,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,108,109,252,109,252,108,252,107,107,107,252,107,252,107,252,107,252,107,106,107,107,107,107,107,106,106,107,106,107,106,106,106,107,106,106,106,106,106,106,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,108,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,107,109,107,109,252,107,109,107,252,107,109,107,109,107,109,107,107,107,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,202,202,202,203,202,203,204,202,202,203,203,204,204,204,203,204,204,204,205,215,205,215,205,215,205,213,205,215,205,215,205,213,205,213,205,213,205,213,205,213,206,214,214,206,206,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,150,150,149,232,149,149,149,150,150,149,144,146,146,147,144,115,115,115,115,116,115,115,115,116,115,113,113,113,113,113,113,113,113,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,157,157,157,157,156,156,155,157,157,157,156,155,155,156,155,156,156,157,157,157,157,157,156,156,157,157,156,156,155,157,156,156,155,155,156,156,155,202,202,203,202,203,203,204,202,202,202,203,203,204,204,203,203,204,203,204,199,192,193,194,203,204,203,204,203,204,204,157,156,156,155,156,155,155,202,203,203,204,202,199,199,192,192,193,192,193,192,193,192,192,192,193,192,193,193,194,193,194,195,195,192,192,192,193,192,195,193,195,195,195,193,195,194,194,192,192,192,193,192,193,192,193,192,193,194,195,194,195,195,195,193,195,199,192,192,193,192,193,192,193,193,193,192,193,192,192,192,193,192,193,192,193,193,194,193,192,193,194,194,193 +,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,109,109,252,107,252,252,252,252,108,252,107,107,107,107,107,107,107,107,252,107,252,107,106,107,106,107,106,106,107,106,107,107,106,106,107,106,107,106,106,106,106,106,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,108,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,107,107,107,109,109,107,107,107,109,109,109,107,109,107,107,107,107,107,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,202,202,202,202,203,202,203,202,204,202,203,203,204,203,204,204,215,205,215,215,215,205,213,215,215,205,215,215,215,205,215,215,215,205,215,215,215,205,213,213,213,205,206,214,206,206,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,150,145,147,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,150,150,149,149,149,149,149,150,150,113,113,113,113,113,116,115,116,115,116,116,116,116,116,116,116,116,117,117,117,117,117,117,116,116,113,113,113,113,113,114,114,114,114,114,114,114,114,114,114,114,157,156,157,156,156,156,155,157,155,157,156,155,156,156,155,156,156,157,157,157,157,157,156,155,155,157,156,156,156,157,157,156,156,155,156,155,156,202,202,202,203,203,203,203,202,202,203,203,204,204,204,204,204,204,203,199,192,192,193,193,194,204,204,204,204,204,204,157,157,156,156,155,155,203,203,203,204,202,199,199,192,192,192,192,193,193,193,193,192,192,192,192,193,193,193,193,194,194,195,195,192,192,192,192,193,193,193,195,195,193,195,195,194,194,192,192,192,192,192,193,192,192,192,192,193,194,195,195,195,195,195,199,199,192,192,192,193,193,193,193,193,193,192,192,192,192,192,192,193,193,193,192,193,193,193,193,194,194,194,193 +,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,109,109,109,108,109,252,252,252,108,252,107,252,107,107,107,252,107,252,107,252,107,252,107,106,107,106,106,106,106,107,107,107,106,107,106,107,106,106,106,106,106,106,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,108,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,252,109,107,107,252,109,109,109,252,109,252,107,109,107,109,107,109,107,107,107,107,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,202,202,203,202,203,202,203,203,202,202,202,202,204,204,204,204,215,204,215,205,215,205,215,205,213,205,215,205,215,205,215,214,214,205,2,205,213,205,215,205,213,206,214,205,206,214,206,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,150,144,147,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,2,2,2,3,113,113,113,113,113,113,113,113,115,116,115,116,115,116,116,116,116,116,116,117,116,117,116,117,116,117,117,117,116,117,116,117,116,117,116,117,116,117,116,113,113,113,113,113,113,113,113,113,113,157,157,156,157,157,156,156,155,157,157,157,155,155,156,156,155,155,156,157,157,157,157,157,156,156,155,157,156,156,155,157,156,156,155,156,155,202,202,202,202,203,203,204,203,202,202,203,202,203,203,204,204,204,204,199,199,192,192,193,193,194,193,194,203,204,204,204,204,204,156,157,155,156,192,194,194,204,204,203,199,192,199,193,192,193,192,193,192,193,192,193,192,193,193,194,193,194,194,194,195,192,192,193,192,193,193,195,193,195,195,195,193,194,194,192,192,192,192,192,192,192,192,193,192,193,193,195,195,195,194,195,195,199,192,193,192,193,192,193,192,193,193,194,192,193,192,193,192,193,192,192,192,193,193,194,193,194,193,194,193,193 +,252,252,252,252,252,252,252,108,109,252,252,252,252,252,252,252,252,252,109,109,109,108,252,252,252,252,252,252,107,107,107,107,107,107,252,107,252,107,252,107,252,107,106,107,106,106,107,106,107,107,106,106,107,106,107,106,106,106,106,106,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,252,108,252,252,252,252,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,252,109,252,107,107,252,107,109,107,109,252,109,252,107,252,252,109,109,107,107,107,107,107,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,202,202,202,202,202,203,202,202,204,202,203,202,204,204,204,215,204,215,215,215,205,213,215,213,215,215,215,215,213,215,213,214,214,215,2,2,205,215,215,215,215,213,213,215,213,206,214,206,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,150,144,147,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,113,113,115,115,115,115,115,115,115,115,115,116,115,116,116,116,116,116,116,116,116,116,116,117,117,117,117,117,117,116,116,116,116,116,116,117,116,117,116,117,117,117,117,117,117,117,117,117,117,117,117,117,157,157,156,157,156,156,156,157,157,156,155,155,156,156,155,155,155,157,157,157,157,157,156,156,155,155,156,157,155,156,157,157,156,156,155,202,202,202,202,202,202,203,203,204,202,202,202,203,203,203,204,204,199,199,192,192,192,193,193,193,193,194,194,204,204,204,204,204,204,157,156,192,192,193,193,194,194,194,199,199,192,192,192,193,193,194,192,193,193,192,192,193,193,193,193,194,194,194,195,195,192,192,192,193,193,193,193,195,195,195,193,194,194,194,192,192,192,192,192,193,192,192,193,193,195,195,194,195,195,195,195,195,199,192,192,193,192,193,193,193,193,193,193,192,192,192,192,192,192,192,192,193,193,193,193,194,194,194,193,194,194 +,252,252,252,252,252,252,108,109,252,252,252,252,252,252,252,252,252,252,109,252,108,252,108,252,109,252,252,252,252,107,107,252,107,252,107,252,107,252,107,252,107,252,107,106,107,106,107,107,107,107,106,106,106,107,106,106,106,106,106,106,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,108,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,107,107,252,109,252,109,107,109,252,109,252,252,252,252,252,107,109,107,107,107,107,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,202,202,203,202,203,202,202,203,204,203,204,203,204,203,204,204,215,215,215,205,215,205,213,205,215,205,215,205,213,213,214,214,2,2,2,205,213,205,213,205,213,205,213,213,215,214,206,206,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,1,2,2,2,150,144,147,2,1,2,2,2,1,2,1,2,1,2,2,2,1,2,1,2,113,113,113,116,113,113,113,115,115,117,117,117,117,117,116,117,116,117,117,116,115,116,116,117,116,117,116,117,116,117,116,116,116,117,116,117,116,117,116,117,116,117,116,117,116,117,116,117,116,117,116,117,116,117,117,117,117,117,117,157,157,156,157,157,156,156,157,157,156,156,155,156,155,156,155,155,157,157,157,157,157,157,156,156,155,157,156,155,157,157,156,156,155,202,202,202,202,202,202,203,202,203,202,202,202,203,202,203,203,204,199,199,192,192,192,193,193,193,193,194,193,194,194,204,204,204,204,204,192,192,192,193,193,194,193,194,193,199,192,199,192,193,192,194,194,193,192,193,192,193,192,193,193,194,193,194,194,195,195,193,192,193,192,193,193,195,195,195,193,195,193,194,192,193,192,192,192,193,192,192,192,193,193,195,195,195,194,195,194,195,193,199,192,193,192,193,192,193,193,194,193,194,192,193,192,192,192,192,192,193,192,193,193,194,193,194,194,194,194,194 +,252,252,252,252,252,252,108,108,252,252,252,252,252,252,252,252,252,252,109,109,108,108,252,109,252,252,252,252,252,107,107,107,107,107,107,107,252,107,252,107,252,107,252,107,106,107,252,107,107,107,106,106,107,106,107,106,106,106,106,106,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,252,108,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,252,252,252,107,109,109,109,109,252,109,252,109,252,252,252,252,252,252,107,107,107,107,107,107,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,202,202,202,202,203,203,203,202,202,204,203,202,204,204,204,204,215,204,215,215,215,215,213,215,215,215,213,205,213,213,213,213,2,2,2,1,215,215,215,215,213,213,213,205,213,213,214,214,206,214,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,150,144,147,2,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,115,115,116,117,115,115,115,115,116,116,117,117,117,116,117,117,117,117,116,116,117,117,117,116,117,117,116,116,117,117,117,116,116,116,116,116,117,116,116,116,117,116,116,116,117,117,117,116,117,117,117,117,117,117,117,117,117,117,117,157,157,156,157,156,156,155,157,156,156,155,155,156,156,155,156,155,157,157,157,157,157,156,156,155,155,156,156,155,157,157,156,156,156,202,202,202,202,202,202,202,203,202,202,202,203,203,203,203,204,199,192,192,192,192,193,193,193,193,193,193,194,194,194,194,204,204,192,192,193,193,193,193,193,194,194,194,199,199,192,192,193,192,193,193,194,193,193,192,192,192,193,193,193,193,194,194,194,194,195,192,192,192,193,193,195,195,193,193,195,194,194,192,192,192,193,192,192,192,192,192,193,194,193,194,195,194,195,195,195,195,199,199,192,192,192,192,193,193,193,193,194,194,192,192,192,192,192,192,192,192,193,193,194,194,194,194,193,194,194,193 +,252,252,252,252,252,252,108,109,252,252,252,252,252,252,252,252,252,252,109,109,108,252,108,252,252,252,252,252,252,107,107,107,107,252,107,252,107,252,107,252,107,252,107,252,107,106,107,252,107,252,106,106,106,107,106,107,106,106,106,106,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,108,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,107,107,107,252,109,252,109,252,109,252,109,252,109,252,252,252,107,107,107,109,107,107,107,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,202,203,202,203,202,203,202,202,202,203,204,204,203,204,203,204,204,215,215,215,215,215,205,215,205,215,205,213,213,214,213,214,1,2,1,2,215,215,205,215,205,213,205,213,213,214,205,206,214,206,214,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,150,149,149,144,147,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,115,115,116,117,115,115,115,116,116,117,117,117,116,117,116,117,117,117,116,116,116,117,116,117,117,117,116,117,117,116,117,116,116,117,116,117,116,117,116,117,113,113,113,114,113,114,114,114,114,114,114,114,114,114,114,114,114,114,157,157,156,156,157,157,156,156,157,157,156,156,155,156,156,156,156,155,157,157,157,157,157,157,155,155,156,156,155,155,156,157,156,156,155,203,202,202,202,203,202,202,202,202,202,202,202,203,203,204,199,192,192,192,192,193,192,193,193,194,193,194,193,194,194,194,192,192,192,193,193,193,193,194,193,194,193,194,199,192,192,192,192,193,193,194,194,193,192,192,192,193,192,193,193,194,193,194,194,194,195,193,193,192,193,195,192,195,193,195,193,194,194,192,192,193,192,192,192,193,192,193,192,195,193,195,195,195,194,195,195,195,192,192,192,193,192,193,193,194,193,194,192,194,192,193,192,193,192,193,192,193,192,193,193,194,193,194,194,194,193,193 +,252,252,252,252,252,252,108,108,109,252,252,252,252,252,252,252,252,252,109,109,108,108,252,109,252,252,252,252,252,252,252,107,107,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,107,107,106,106,106,106,107,106,106,106,106,106,1,2,1,2,1,2,1,2,1,2,1,2,1,2,108,252,108,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,107,107,252,109,109,109,109,109,252,109,252,252,252,252,252,252,252,107,107,107,107,107,107,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,202,202,202,202,203,203,202,203,204,202,204,203,204,204,204,204,204,215,215,215,215,215,213,215,215,215,215,213,213,213,214,214,2,1,2,1,2,215,215,215,215,215,215,215,213,213,215,214,214,206,214,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,150,149,149,149,144,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,115,115,115,116,117,115,115,116,115,116,116,117,117,116,116,117,117,117,116,116,116,116,116,117,117,117,117,117,117,117,115,116,117,113,113,113,113,113,113,113,113,113,116,116,116,116,116,116,116,116,116,116,116,116,116,117,117,117,117,157,157,156,156,157,156,156,157,157,156,156,155,155,156,156,155,156,157,157,157,157,157,157,156,155,156,156,156,156,155,157,156,156,156,156,202,202,202,202,202,202,202,202,202,203,202,202,202,203,203,199,192,192,192,193,193,193,193,193,193,194,194,194,194,194,192,192,192,193,193,193,193,193,193,194,194,194,199,192,199,192,192,193,193,193,194,194,193,192,192,193,192,193,193,193,193,194,194,194,194,195,192,193,192,195,193,193,193,195,195,194,194,192,192,192,192,192,192,192,192,193,193,194,194,195,195,194,194,195,195,195,195,192,192,192,192,193,193,193,193,194,192,193,193,194,192,192,192,192,192,193,193,193,193,193,193,194,194,194,193,194,193 +,252,252,252,252,252,108,108,252,108,252,252,252,252,252,252,252,252,252,109,252,107,252,108,252,108,252,252,252,252,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,106,107,106,106,107,106,106,106,106,2,1,2,1,2,1,2,1,2,1,2,1,2,1,252,108,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,107,107,107,107,252,109,252,109,252,109,252,252,252,252,252,107,107,107,109,107,109,107,107,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,202,202,203,202,203,202,203,203,202,204,202,203,204,203,204,203,204,204,204,215,215,215,213,215,215,215,213,215,213,213,214,213,214,1,2,1,2,1,215,215,215,215,213,215,213,215,213,205,214,213,214,206,214,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,115,115,112,113,113,113,2,1,2,1,2,1,2,1,2,1,2,1,2,1,115,115,115,117,115,115,115,115,116,116,117,117,116,116,117,117,117,117,116,116,117,116,117,117,117,116,117,117,115,115,116,116,115,117,115,115,116,115,116,116,117,116,117,116,117,157,151,152,152,115,116,115,116,116,116,116,117,116,117,157,157,156,155,157,157,156,157,156,156,155,156,155,156,156,157,157,157,157,157,157,157,156,155,156,157,156,156,155,156,155,157,156,156,202,202,202,202,202,202,202,202,202,203,202,202,202,204,204,199,192,193,192,193,192,193,193,193,193,194,193,194,193,194,194,192,192,193,192,193,192,193,193,194,193,194,194,199,192,192,192,193,192,193,193,194,194,193,192,193,192,193,193,194,193,194,193,194,194,194,194,193,192,193,192,193,193,195,193,194,193,194,192,193,192,193,192,192,192,193,192,194,194,195,194,195,194,195,194,195,195,193,192,193,192,193,192,193,193,192,192,193,193,194,193,194,192,192,192,193,192,193,193,193,193,194,193,194,193,194,193,193 +,252,252,252,252,252,108,108,108,252,252,252,252,252,252,252,252,252,252,109,109,108,108,108,108,252,252,252,252,252,252,252,107,252,107,107,107,252,252,252,252,109,107,252,107,252,107,252,107,252,107,107,106,107,107,106,106,107,106,106,106,1,1,1,1,1,1,1,1,1,1,1,1,1,1,108,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,107,107,107,109,109,252,109,252,109,252,252,252,252,252,252,252,107,107,107,107,107,109,107,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,202,202,202,202,202,203,203,204,204,203,202,203,203,204,203,204,203,204,204,204,215,215,215,215,215,215,215,213,213,214,214,214,214,1,1,1,1,1,215,215,215,215,213,213,213,215,213,214,214,214,214,214,214,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,115,115,115,117,112,113,113,1,1,1,1,1,1,1,1,1,1,1,1,1,1,115,115,115,117,115,116,115,116,116,116,117,117,116,117,117,116,116,117,116,117,116,117,117,117,117,117,117,117,115,115,116,116,117,116,116,116,116,117,117,115,115,116,116,117,157,157,156,151,152,115,115,115,115,116,116,116,116,117,117,157,156,156,155,157,157,157,157,156,155,156,155,155,157,157,157,157,157,157,157,157,156,156,155,157,156,156,156,156,155,155,156,156,155,202,202,202,202,202,202,203,202,202,203,202,204,203,203,199,192,192,192,192,192,193,193,193,193,193,193,193,193,194,194,194,192,193,192,193,193,193,193,193,193,194,194,199,192,192,192,193,192,193,193,193,193,194,193,192,192,193,193,193,193,194,192,193,193,194,194,194,192,193,193,193,193,195,193,195,194,194,192,192,192,193,193,192,192,193,194,194,194,194,195,195,194,195,195,195,195,195,192,199,192,193,193,193,193,192,192,193,193,193,193,194,194,194,192,192,192,193,193,193,193,194,194,197,193,193,193,194,193 +,252,252,252,252,252,108,108,252,108,252,252,252,252,252,252,252,252,252,109,252,107,252,108,252,108,252,108,252,252,252,252,252,107,252,107,252,107,252,107,109,109,252,107,252,107,252,107,252,107,252,107,107,107,107,106,106,106,106,106,106,1,1,2,1,1,1,2,1,1,1,2,1,1,1,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,107,107,107,252,107,252,109,252,109,252,109,252,109,252,252,252,107,252,107,109,107,107,107,107,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,202,202,203,202,202,202,203,203,204,203,202,203,204,203,204,203,204,203,204,203,204,215,215,215,215,215,213,215,213,213,214,214,214,1,2,1,1,1,215,215,215,215,213,215,213,215,213,214,213,214,214,213,214,214,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,115,116,115,116,112,112,113,113,1,1,1,2,1,1,1,2,149,112,112,112,1,115,115,116,115,116,115,116,115,116,116,117,117,116,116,117,116,117,117,117,116,117,116,117,116,117,117,117,115,116,116,117,116,117,116,115,116,117,116,117,116,117,117,115,157,157,157,156,151,151,152,115,115,117,117,116,115,116,116,117,157,157,155,155,157,157,157,157,156,155,155,155,157,157,157,157,157,157,157,157,157,157,155,155,156,157,156,156,155,155,155,156,155,156,202,203,202,202,202,203,202,203,202,203,202,203,203,199,199,192,192,193,192,193,192,193,192,193,193,194,193,194,193,194,194,192,192,193,192,193,193,194,193,194,194,194,199,192,192,192,192,193,192,193,193,194,194,193,192,193,192,193,192,193,192,193,192,194,193,194,193,195,192,193,192,193,193,195,193,194,192,193,192,193,192,192,192,193,192,194,194,194,194,195,195,195,194,195,195,195,195,192,192,193,192,193,193,192,192,193,192,193,193,194,193,194,194,194,192,193,192,193,193,194,196,193,196,193,193,193,193,194 +,252,252,252,252,109,108,108,108,252,252,252,252,252,252,252,252,252,109,109,252,252,107,108,108,252,108,252,252,252,252,252,107,252,107,252,107,107,107,109,109,109,109,252,107,252,107,252,107,109,107,252,107,107,107,107,106,106,106,106,106,1,1,1,1,1,1,1,1,1,1,1,1,1,1,108,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,109,109,109,109,252,109,252,109,252,252,252,252,252,107,107,107,107,107,107,107,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,202,202,202,202,202,203,203,204,204,203,202,203,203,203,203,204,203,204,204,204,215,204,215,215,215,215,215,213,213,213,214,214,1,1,1,1,1,1,215,215,215,215,215,213,213,215,213,214,215,213,214,214,214,214,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,115,115,115,115,116,112,116,112,113,1,1,1,1,1,1,149,149,149,149,149,112,115,115,115,115,115,115,116,116,116,116,116,116,117,116,117,116,116,116,117,116,117,117,117,117,117,117,115,115,116,116,116,117,117,116,115,116,117,117,117,116,117,117,117,157,157,157,157,156,156,151,152,115,116,115,116,116,116,116,116,157,157,156,156,157,157,157,157,157,156,155,155,157,157,157,157,156,157,157,157,157,156,156,155,157,157,156,156,156,156,155,155,156,156,155,202,202,202,202,202,202,202,202,203,202,203,203,199,199,192,192,192,192,193,192,193,193,193,193,193,193,194,194,194,194,194,192,192,192,193,193,193,193,194,194,194,199,192,192,192,192,193,192,193,193,194,194,194,193,193,192,192,192,193,193,192,192,193,193,194,194,195,195,193,192,193,193,193,193,194,192,192,192,193,192,192,192,193,193,193,193,194,194,195,195,195,195,195,195,195,195,194,192,192,192,193,193,192,192,192,192,193,193,193,193,194,194,194,194,193,193,193,193,196,196,193,193,193,193,194,193,194,194 +,252,252,252,252,252,108,108,252,108,252,252,252,252,252,252,252,252,109,109,252,252,108,107,252,108,252,108,252,108,252,252,252,107,252,107,252,252,109,109,252,109,107,107,252,107,252,107,109,107,107,107,252,107,107,107,107,106,107,106,106,19,19,19,19,19,19,19,19,19,19,19,19,19,19,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,252,107,252,107,252,109,252,109,252,109,252,109,252,109,252,252,252,107,107,107,109,107,109,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,202,202,202,203,202,202,202,203,203,204,203,202,202,203,202,203,203,204,203,204,204,204,215,215,215,215,215,213,215,214,213,214,213,19,19,19,19,19,215,215,215,212,215,215,215,213,215,213,213,214,213,214,213,215,214,214,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,115,115,115,117,117,112,117,116,112,112,19,19,19,19,149,149,149,149,115,115,112,112,112,115,115,115,116,115,116,116,116,116,117,116,117,117,117,116,117,116,117,116,117,117,117,115,115,115,116,116,117,116,117,115,116,115,116,116,117,116,115,117,117,157,157,157,157,157,156,155,151,152,116,115,116,115,116,115,116,115,157,156,156,157,155,157,157,157,156,155,155,157,157,157,157,156,156,157,157,156,157,155,157,157,157,156,157,156,156,155,156,155,156,155,202,202,203,202,203,202,203,202,203,202,202,203,204,199,192,192,192,192,192,192,193,192,193,192,194,192,194,193,194,193,194,192,193,192,193,193,192,192,193,193,194,194,192,192,192,192,193,192,193,192,193,193,194,194,194,193,194,192,193,193,193,192,193,192,194,193,194,195,195,192,193,193,195,193,194,193,192,192,193,192,192,192,193,192,193,193,193,194,194,194,195,195,195,194,195,194,195,194,192,192,193,192,192,192,193,192,193,192,193,193,194,193,194,193,194,192,193,192,193,196,193,196,193,193,194,193,194,194,194 +,252,252,252,252,109,108,108,108,252,252,252,252,252,252,252,252,252,252,109,109,109,107,108,108,252,108,252,107,252,252,252,252,252,107,252,107,109,107,109,109,252,109,252,107,252,107,252,107,109,107,107,107,252,109,109,107,107,106,107,106,106,20,20,20,20,20,20,20,20,20,20,20,20,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,109,107,109,109,252,109,109,109,252,252,252,252,252,252,252,107,252,107,107,107,107,107,107,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,202,202,202,202,202,202,203,203,204,204,202,202,202,202,203,203,203,203,204,204,204,215,204,215,215,215,215,215,213,213,214,214,214,20,20,20,20,215,215,215,215,215,215,215,213,213,215,213,213,215,213,213,214,205,214,214,214,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,115,115,115,115,117,115,117,112,117,112,112,112,112,112,116,115,116,116,117,116,115,115,116,116,115,115,115,115,116,116,116,116,117,116,117,117,117,117,117,117,117,117,117,117,115,115,115,115,116,116,116,116,117,115,116,117,116,116,116,116,115,117,117,157,157,157,157,157,157,156,156,151,151,155,115,115,116,116,116,116,117,157,156,157,157,156,155,157,157,155,155,157,157,157,157,157,157,156,157,156,157,155,157,157,157,157,157,156,156,156,156,155,155,155,155,202,202,202,202,202,203,203,202,202,203,202,204,199,192,192,192,192,192,192,192,192,192,192,192,192,194,194,194,194,194,192,192,192,192,192,193,193,193,193,194,194,199,192,192,192,192,192,193,192,193,193,194,194,194,192,193,192,193,192,193,192,193,192,194,193,194,194,195,195,193,193,193,193,194,194,192,192,193,192,193,192,192,192,193,193,193,193,194,194,195,195,195,195,195,195,195,195,199,192,192,192,193,192,192,192,193,193,193,193,193,193,194,193,194,194,192,192,193,192,193,193,193,193,194,193,194,193,194,194 +,252,252,252,252,252,108,108,252,108,252,252,252,252,252,109,252,252,252,109,109,109,252,107,108,108,252,108,252,107,252,109,252,252,252,107,252,107,109,107,109,109,252,109,107,107,252,107,252,107,107,107,252,109,109,107,109,107,107,106,106,106,106,20,20,20,20,20,20,20,20,20,20,20,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,107,107,107,107,107,109,107,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21,202,202,202,203,202,203,202,203,203,204,202,203,202,203,203,204,203,204,204,204,204,204,215,204,215,215,213,215,214,215,215,214,214,20,20,20,215,215,215,212,215,213,215,215,215,215,215,215,215,215,214,214,214,215,213,214,214,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,115,115,116,115,116,117,115,116,112,116,117,112,116,115,115,115,116,116,117,115,117,115,116,115,117,115,116,115,116,116,117,116,117,116,117,116,117,115,117,115,116,116,117,115,115,115,115,115,116,115,115,115,117,115,116,116,117,115,116,116,117,115,117,157,157,157,157,155,151,157,156,155,156,151,152,116,117,116,117,116,117,117,157,155,157,156,156,155,157,156,155,155,157,157,157,157,157,156,157,156,157,155,157,156,157,157,157,156,157,156,156,155,156,155,155,155,202,202,203,202,203,202,203,202,203,202,202,199,199,192,192,192,193,193,192,192,194,192,193,192,193,193,194,193,194,193,192,192,192,192,193,192,193,193,194,193,194,192,192,192,192,192,193,192,193,193,194,194,194,192,192,192,193,192,193,192,193,192,194,193,194,194,194,195,195,192,193,193,194,193,192,192,193,192,193,192,192,192,193,192,193,193,194,193,194,194,195,194,195,195,195,195,194,193,193,192,193,192,197,192,193,192,193,192,193,193,198,193,194,194,198,192,193,193,197,192,193,193,194,193,194,193,194,193,194 +,252,252,252,252,109,108,108,108,109,252,252,252,252,252,252,252,252,252,109,109,109,109,109,107,108,108,252,252,252,252,252,252,252,107,252,107,252,107,109,109,109,109,109,107,107,107,252,107,109,109,107,107,107,109,109,107,107,107,107,106,106,106,106,20,20,20,20,20,20,20,20,20,20,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,107,107,107,107,107,107,107,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,202,202,202,203,203,204,203,204,203,202,204,202,202,203,203,203,203,204,204,204,204,204,204,204,215,215,215,215,215,213,214,215,213,214,20,20,20,215,215,215,215,212,215,215,215,215,215,213,215,213,215,214,213,214,215,213,213,214,213,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,115,115,115,115,115,115,116,116,115,117,112,117,112,116,115,115,115,116,116,116,115,117,117,116,116,117,115,115,115,116,116,116,117,117,117,116,116,117,115,116,116,117,115,115,115,115,115,116,115,115,115,115,115,116,115,117,116,117,117,117,116,116,115,116,157,157,157,157,156,156,155,151,156,156,156,155,151,155,116,117,117,117,157,156,156,157,156,156,155,155,157,155,156,157,157,157,157,157,156,157,157,156,156,155,156,157,157,157,157,157,156,155,156,157,156,156,155,155,202,202,202,202,202,203,203,202,202,203,199,199,192,192,192,192,192,193,193,193,192,192,192,193,193,192,193,194,194,194,192,192,192,193,193,193,193,193,193,194,192,192,192,193,192,193,193,193,193,193,194,194,192,192,192,192,192,193,192,194,193,193,193,194,194,194,195,195,195,195,193,193,194,192,192,193,192,192,192,193,192,193,193,193,193,193,194,194,194,195,195,195,195,195,195,195,194,192,192,193,192,192,192,193,192,193,193,193,193,193,193,194,194,192,192,192,193,193,193,193,193,193,193,194,193,194,194,194,194 +,252,252,252,252,252,108,108,252,108,252,252,252,252,252,109,252,252,252,252,109,109,109,109,252,107,252,109,252,109,252,252,252,109,252,252,252,107,252,107,109,109,252,109,108,107,252,107,252,109,252,107,107,107,252,107,107,107,107,107,107,106,106,106,20,21,20,20,20,21,20,21,20,21,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,109,107,252,107,252,107,252,109,252,109,252,109,252,109,252,109,252,107,109,107,107,107,107,107,107,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,202,202,202,203,202,203,203,204,204,202,203,202,202,203,202,203,203,204,204,204,203,204,204,204,204,204,215,215,202,215,213,214,215,215,214,21,20,215,215,212,215,212,215,215,215,213,213,213,213,212,205,213,211,213,213,215,205,214,213,214,211,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,115,115,115,115,116,115,115,115,116,116,117,116,112,117,116,115,116,115,116,116,117,115,116,117,117,116,117,115,116,115,115,115,116,116,117,117,116,115,117,115,115,115,116,115,116,115,116,115,116,115,115,115,117,115,116,115,116,116,117,116,117,117,117,117,117,117,157,157,157,156,156,157,155,151,156,155,156,155,155,151,117,117,117,156,157,156,157,156,157,155,156,155,157,156,157,157,157,156,157,157,157,156,157,156,156,155,157,157,157,156,156,155,156,155,155,156,156,155,155,202,202,202,203,202,203,203,204,203,202,196,199,192,192,192,192,192,193,192,193,193,192,192,193,192,192,194,194,193,194,192,192,192,193,192,193,193,194,193,194,193,192,192,193,192,193,193,193,193,193,194,194,192,192,192,192,193,192,192,193,193,194,194,194,194,194,195,195,195,195,195,193,193,192,192,193,192,193,192,192,192,193,193,193,193,193,194,195,194,195,194,195,194,195,197,195,194,194,192,197,192,197,192,193,192,196,192,197,193,197,193,194,193,198,192,197,192,197,193,193,193,197,193,197,193,194,193,197,194,194 +,252,252,252,252,109,108,108,108,252,252,109,252,252,252,252,252,252,252,252,109,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,108,108,252,107,109,109,109,109,107,107,109,109,252,109,252,107,107,109,107,107,107,107,107,107,107,107,106,106,20,20,20,20,20,20,20,20,20,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,109,107,252,109,109,109,252,252,252,109,252,252,252,252,252,107,109,107,107,107,107,107,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,202,202,202,202,202,203,203,203,203,204,204,203,202,202,204,203,202,203,203,203,203,204,204,204,204,204,204,202,204,204,204,215,214,214,215,215,20,20,215,215,215,215,215,215,215,215,215,215,215,213,212,215,215,211,214,213,215,212,213,213,213,213,211,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,80,83,86,89,92,95,115,115,115,116,116,117,116,117,112,116,115,115,115,116,116,116,116,117,117,116,116,117,115,115,116,116,115,116,117,116,116,117,115,116,115,115,115,115,115,115,115,116,116,116,115,115,115,115,115,116,115,115,116,116,117,117,116,117,117,117,117,157,157,156,155,155,157,156,151,155,151,156,155,155,151,151,155,157,157,156,156,156,157,157,156,156,155,155,157,157,157,157,157,157,157,157,155,157,157,156,155,155,157,157,156,156,156,156,155,155,155,156,155,156,155,202,202,202,202,202,203,203,204,204,203,199,192,192,192,192,192,192,192,193,193,193,192,192,192,192,194,193,193,193,192,192,192,193,192,193,193,193,193,194,194,192,192,193,192,193,192,193,193,193,194,194,193,192,192,193,192,193,192,193,192,194,193,194,194,194,195,195,195,195,193,195,193,192,192,193,192,193,192,192,192,193,192,193,193,193,194,195,194,195,195,195,195,195,193,195,195,194,196,193,193,193,192,193,192,193,192,193,193,193,193,194,193,194,194,192,192,193,192,193,193,193,193,193,193,194,193,194,194,193,194 +,252,252,252,252,252,109,108,108,108,252,108,252,252,252,109,252,252,252,252,252,109,252,109,109,109,252,109,252,109,252,109,252,252,252,252,252,107,108,108,109,109,252,109,108,107,252,107,252,107,252,109,109,109,252,107,107,107,107,107,107,107,107,107,106,106,20,21,20,21,20,21,20,21,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,252,107,252,107,252,107,252,109,252,109,252,109,252,109,252,252,109,107,107,107,107,107,107,107,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,202,203,202,203,202,203,203,204,203,204,204,202,202,204,204,203,202,203,203,204,209,202,203,204,209,204,202,202,203,203,203,204,203,213,214,204,215,215,20,215,215,215,215,212,215,212,215,215,215,215,215,213,212,215,212,211,213,215,205,212,212,213,211,213,211,21,20,20,20,20,20,20,35,38,41,44,46,32,34,37,38,41,42,45,46,32,33,48,51,54,57,60,62,44,45,47,32,33,34,36,48,50,51,54,55,58,59,62,62,48,53,58,62,37,38,41,41,44,48,50,51,53,54,57,57,60,61,63,115,115,115,116,115,116,115,116,115,115,115,115,115,116,115,116,115,116,116,117,117,117,117,117,157,157,157,157,156,156,157,157,156,156,155,151,155,156,155,155,155,151,156,157,199,199,199,193,156,156,155,156,157,157,157,157,156,157,157,157,156,155,157,157,156,156,155,157,156,157,156,156,155,156,155,155,155,156,155,155,202,202,202,203,202,203,203,204,202,199,192,193,192,193,192,193,192,193,193,193,193,192,192,192,193,194,193,194,192,192,192,193,192,193,193,194,194,194,193,192,192,193,192,193,192,193,192,194,194,194,194,192,192,193,192,193,192,193,193,193,193,194,194,194,194,195,195,195,195,195,194,194,192,192,193,192,192,192,193,192,193,193,193,193,194,195,194,195,194,192,192,195,193,195,194,195,193,196,192,197,192,197,193,197,192,197,193,197,193,197,194,198,194,198,192,197,193,197,193,197,193,197,193,197,193,197,194,193,194,194 +,252,252,252,252,252,252,108,108,108,108,109,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,108,107,109,109,109,109,107,107,109,107,109,109,252,109,109,109,109,107,107,107,107,107,107,107,107,106,106,20,20,21,20,20,20,20,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,109,107,109,109,252,109,252,109,252,252,252,252,252,252,109,107,109,107,107,107,107,107,107,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,20,21,20,20,20,20,20,20,202,202,202,202,202,203,203,210,208,208,208,208,210,209,209,203,209,203,203,203,203,209,204,209,209,204,203,202,203,203,203,204,204,208,204,211,214,204,215,20,215,215,212,212,215,212,215,215,215,215,215,215,215,213,211,212,215,211,213,215,215,212,212,213,211,213,211,211,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,33,34,35,37,38,39,40,41,42,44,45,46,47,32,34,35,37,39,40,42,44,45,47,32,33,33,34,35,35,36,37,38,38,39,39,40,41,42,42,43,44,44,45,46,48,50,52,55,56,59,61,63,157,157,157,157,157,157,156,156,157,155,156,156,156,151,151,151,151,156,155,155,151,157,192,199,193,197,193,198,156,156,155,157,157,157,157,156,156,155,157,156,155,157,156,155,157,155,156,157,156,156,156,156,155,155,155,156,155,155,155,203,202,203,202,203,203,204,202,199,192,196,192,193,192,196,192,193,192,193,193,192,192,192,193,194,193,193,193,193,192,193,193,193,192,193,194,194,194,192,192,193,192,193,192,193,193,196,193,194,194,197,192,193,192,193,192,193,193,197,193,194,193,194,194,195,195,195,195,197,194,193,192,192,193,192,193,192,192,192,193,193,193,193,194,198,194,195,194,192,192,193,193,193,193,195,194,197,196,193,193,193,193,192,193,193,193,193,193,193,194,194,193,194,192,192,193,193,193,193,193,193,193,193,193,194,194,193,194,198,194 +,252,252,252,252,252,252,107,109,108,252,108,252,108,252,252,252,109,252,252,252,252,109,109,252,109,252,109,252,109,252,109,108,109,252,252,252,252,252,252,108,252,109,109,109,109,108,107,252,107,252,109,252,109,109,109,109,109,107,107,107,107,107,107,107,107,107,21,20,21,20,21,20,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,252,107,252,107,252,109,252,109,252,109,252,109,252,252,252,107,109,107,109,107,107,107,107,107,107,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,202,202,208,202,202,202,209,210,208,203,208,203,208,208,209,202,209,203,203,203,208,208,211,209,208,209,202,210,203,209,203,209,208,209,208,208,211,214,215,20,212,212,212,212,212,215,212,215,215,212,215,215,215,205,213,205,211,212,211,213,215,205,212,212,213,211,213,212,211,211,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,21,36,37,40,32,34,35,37,38,40,41,43,44,46,47,45,45,46,46,47,46,47,157,157,157,157,156,157,156,156,157,157,156,156,155,156,155,156,155,155,151,151,155,155,151,199,193,196,193,193,198,198,198,198,156,156,155,156,155,155,155,157,156,156,155,155,157,156,155,157,156,156,155,156,155,156,155,155,155,156,155,203,202,203,202,203,203,204,202,199,192,196,192,196,193,193,196,196,193,194,193,194,192,193,193,194,192,193,192,193,192,193,192,193,193,193,193,194,194,195,192,192,192,193,192,193,193,194,194,194,194,194,192,192,192,192,193,193,193,193,193,193,193,194,194,194,195,195,195,198,194,193,192,192,193,192,193,192,192,192,193,192,193,193,194,198,194,195,194,192,192,193,192,193,193,195,194,195,195,196,193,197,192,197,193,196,192,197,193,197,194,198,194,198,193,198,192,197,193,197,193,197,193,197,193,197,193,198,194,198,194,194 +,252,252,252,252,252,252,108,108,108,108,109,108,252,252,252,109,252,252,252,252,108,107,108,107,109,107,109,107,252,109,252,109,252,252,252,252,252,252,252,109,108,252,252,252,109,107,108,107,107,107,107,107,107,107,107,107,109,109,107,107,107,107,107,107,107,107,107,20,20,21,20,21,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,107,252,109,109,109,252,252,252,252,252,252,252,107,109,107,109,107,109,107,107,107,107,107,107,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,21,20,20,20,21,20,21,20,202,210,210,210,208,210,210,209,209,208,208,203,203,203,208,208,208,203,203,209,208,208,208,208,211,209,210,209,210,208,203,209,208,208,209,209,208,208,211,214,215,212,212,212,215,212,215,212,212,212,215,212,212,215,212,215,215,212,211,211,211,213,212,215,212,212,211,211,211,211,211,211,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,21,21,21,21,21,21,21,21,41,42,43,44,45,46,47,43,43,45,45,46,47,156,156,156,156,156,156,156,155,155,156,156,155,155,156,155,155,155,155,155,151,151,155,155,155,155,199,196,193,196,193,193,198,198,198,156,156,156,156,156,155,155,155,156,155,155,156,156,155,155,156,156,156,156,156,156,155,155,155,155,155,155,202,203,202,203,203,204,202,199,192,196,192,196,193,196,193,196,193,193,194,194,192,193,193,194,194,193,192,193,192,193,193,193,193,194,194,194,194,194,192,192,192,193,192,193,193,196,194,197,193,196,193,192,192,193,192,193,193,197,193,197,193,197,193,194,195,195,195,198,198,193,194,192,193,193,194,194,192,192,193,193,193,193,193,198,198,197,194,192,192,192,192,193,193,193,194,195,194,196,196,197,193,193,193,196,193,193,193,197,194,194,194,198,194,194,192,197,192,193,193,197,193,193,193,197,194,194,194,194,194,194,194 +,252,252,252,252,252,252,107,108,108,252,108,252,108,252,252,252,252,252,252,108,107,252,107,108,107,252,107,252,107,252,107,252,109,252,107,252,252,252,109,252,109,252,109,252,107,252,107,108,107,252,107,107,107,252,107,109,107,252,107,252,107,107,107,107,107,107,107,106,107,20,21,20,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,252,107,252,107,252,107,252,109,252,109,252,252,252,109,109,107,109,107,109,107,107,107,107,107,107,107,107,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,210,210,209,209,208,209,210,210,209,209,208,210,203,203,208,209,208,208,203,203,208,209,208,209,208,211,208,209,209,209,210,210,208,209,208,209,208,209,208,215,211,214,212,212,212,212,212,212,212,212,212,212,212,212,212,212,215,215,212,212,211,211,211,212,211,215,215,205,211,211,211,211,211,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,21,21,45,46,46,47,32,38,37,38,38,39,38,39,40,156,156,156,156,156,156,156,155,156,155,156,156,156,155,155,155,155,155,155,155,155,155,155,155,151,151,151,192,196,193,196,197,193,193,198,198,198,198,156,155,156,155,156,155,156,155,156,155,156,155,156,155,157,156,156,155,156,155,156,155,155,155,155,155,203,203,203,202,203,203,203,199,196,193,196,193,196,196,196,196,193,193,194,193,193,193,194,194,192,192,193,196,193,193,193,193,194,193,194,194,195,192,192,192,193,192,193,193,193,194,197,193,196,194,192,192,192,192,193,193,193,193,197,193,193,193,194,194,195,195,198,195,193,193,192,193,192,193,193,194,192,193,192,193,193,193,194,194,193,194,192,192,193,192,193,193,195,193,195,194,197,196,196,193,197,193,196,193,197,193,197,194,198,194,198,194,198,193,197,193,197,193,197,193,197,193,197,193,197,193,198,194,198,194,198 +,252,252,252,252,252,252,108,107,108,108,109,252,109,252,252,252,252,252,108,107,108,107,108,107,108,107,109,108,109,107,109,109,109,109,252,252,252,252,252,252,252,109,252,107,252,107,252,107,252,107,107,107,107,107,107,107,107,107,109,107,252,107,107,107,107,107,107,107,106,107,21,21,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,109,107,252,109,252,252,252,252,252,252,109,107,109,107,109,107,109,107,107,107,107,107,107,107,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,202,202,209,209,209,209,208,210,209,209,208,210,210,210,209,209,208,208,208,203,209,209,208,209,208,208,211,208,209,209,208,210,209,209,208,208,209,209,208,208,208,215,211,211,212,212,212,212,212,212,212,212,212,215,212,215,215,212,212,212,212,212,211,211,212,212,211,212,212,212,212,211,211,211,211,20,21,20,21,20,21,21,21,20,21,20,21,20,21,21,21,20,21,20,21,20,21,21,21,20,21,20,21,20,21,21,21,20,21,20,21,20,21,20,21,20,21,20,21,20,44,20,45,20,32,34,36,37,40,41,43,45,32,33,34,35,37,38,39,40,41,47,47,53,54,56,57,59,60,62,63,48,49,51,52,54,55,57,58,60,61,63,48,50,52,58,60,61,63,48,50,52,54,55,199,193,196,193,193,193,197,198,198,197,198,198,155,155,155,155,155,155,155,155,155,155,155,155,155,156,156,156,156,155,155,155,155,155,155,155,155,202,203,202,203,203,203,199,196,193,196,196,196,197,196,196,197,197,194,194,193,193,193,193,196,192,193,196,193,193,193,193,193,193,194,195,195,193,192,192,193,192,193,193,196,196,197,194,197,196,193,194,192,193,193,193,192,193,197,193,197,193,196,194,195,194,198,195,197,193,193,192,192,192,192,193,192,193,193,193,193,193,194,194,198,194,192,192,193,192,193,193,193,193,195,195,197,197,196,196,196,193,196,193,193,193,197,193,197,194,198,194,194,194,197,193,197,192,197,193,193,193,197,193,197,193,198,194,198,194,198,194 +,252,252,252,252,252,252,252,108,107,109,108,252,108,252,252,252,252,252,108,108,107,108,107,109,107,252,107,109,108,109,108,252,107,109,109,252,109,252,252,252,252,252,252,252,107,252,107,252,252,252,109,252,107,107,107,252,107,252,107,109,107,252,107,107,107,107,107,107,107,106,107,107,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,107,252,107,252,107,252,109,252,109,252,109,252,107,109,107,109,107,109,107,109,107,107,107,107,107,107,107,21,20,21,20,21,21,21,20,21,20,21,20,21,20,21,20,21,21,21,20,21,20,21,20,21,20,21,20,21,21,21,20,21,20,21,20,21,20,21,20,21,21,21,20,21,20,21,20,21,20,21,20,21,21,21,20,21,20,21,20,21,20,21,20,21,21,21,20,21,20,21,20,21,20,21,20,21,21,21,20,21,20,21,20,21,20,21,20,21,21,21,20,21,20,21,20,21,20,21,20,21,21,21,20,21,20,21,20,21,20,21,20,21,21,21,20,21,20,21,20,21,20,21,20,21,21,21,20,21,20,21,20,21,20,21,20,21,21,21,20,21,20,21,20,21,20,21,20,21,21,21,20,21,20,21,20,210,210,209,210,209,209,208,208,208,208,209,210,209,209,208,208,209,210,203,203,209,209,209,209,208,209,208,209,211,209,208,209,208,209,209,208,208,209,208,209,208,208,208,215,211,212,212,212,212,212,212,212,212,212,212,215,211,215,215,212,212,212,212,212,211,211,211,212,212,212,212,212,211,212,211,212,211,211,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,47,32,34,35,38,39,42,43,45,32,35,37,40,42,45,47,62,63,48,49,52,53,56,57,60,61,63,48,50,51,54,55,58,59,61,63,48,49,52,53,56,57,60,61,63,199,196,193,196,193,197,197,198,197,198,197,198,198,156,155,155,155,155,155,156,156,156,155,155,155,156,155,155,155,155,155,155,155,155,155,155,203,203,203,203,203,203,196,192,196,196,196,196,196,196,196,197,196,193,197,194,194,193,193,192,192,193,196,193,196,193,193,194,193,194,194,195,195,192,192,193,192,193,193,197,193,196,194,197,196,196,194,192,193,192,193,194,194,196,193,197,193,197,194,194,194,195,195,197,193,193,192,193,193,192,193,193,193,193,193,193,194,194,194,198,194,193,194,193,192,193,193,195,193,195,194,195,194,197,196,197,193,197,193,197,193,198,193,196,194,197,194,198,194,198,193,197,193,197,193,197,193,197,193,197,193,198,193,198,194,198,194,198 +,252,252,252,252,252,252,252,252,108,107,108,108,109,252,109,252,252,252,252,108,108,107,108,107,108,107,108,108,109,108,109,108,252,109,109,109,252,252,252,252,252,252,252,252,252,252,252,107,252,107,252,109,252,107,107,107,107,107,107,107,252,107,252,107,252,252,107,107,108,107,106,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,252,109,252,109,252,252,252,252,252,252,109,107,109,107,109,107,109,107,107,107,107,107,107,107,107,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,210,210,209,209,209,209,208,208,209,209,208,210,209,209,208,210,209,209,209,209,209,209,209,209,209,209,209,209,208,208,208,209,208,208,211,209,208,209,209,209,208,208,208,211,211,208,211,212,212,212,212,212,212,212,212,212,212,212,212,211,212,212,212,212,212,212,211,211,212,212,212,212,211,211,211,211,211,211,211,211,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,41,20,42,43,20,44,45,45,47,47,32,33,34,35,36,37,38,32,33,34,35,36,37,38,40,41,21,42,44,45,46,47,58,58,59,59,60,60,61,61,62,62,63,63,196,196,196,196,197,197,197,197,198,198,198,198,198,198,75,75,76,77,78,78,79,53,53,53,54,156,156,155,156,155,155,155,155,155,155,155,203,202,203,203,203,196,192,196,196,196,196,196,198,198,193,193,193,193,198,194,194,197,192,196,193,196,193,196,193,193,193,193,194,195,195,195,192,192,193,192,193,193,197,193,196,193,196,193,196,193,192,193,194,193,196,193,197,193,197,193,194,193,194,195,195,198,198,193,193,192,193,192,192,193,193,193,193,193,193,198,193,198,198,194,193,192,192,194,193,193,193,193,195,195,195,194,197,196,196,193,197,193,197,193,197,193,197,194,198,194,198,194,197,194,197,193,197,193,197,193,197,193,196,193,197,194,198,194,198,194,198,194 +,252,252,252,252,252,252,252,252,252,108,107,109,108,252,108,252,252,252,252,108,108,109,107,108,107,109,107,109,108,252,108,252,108,252,108,252,109,252,107,252,109,252,109,252,252,252,252,252,107,252,107,252,109,252,107,107,107,252,107,252,107,252,107,252,107,252,107,107,252,108,107,107,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,252,107,252,107,252,107,252,109,252,109,252,252,252,107,109,107,109,107,109,107,107,107,109,107,107,107,107,107,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,210,209,210,209,209,208,208,210,210,208,209,208,210,209,210,209,210,210,210,210,210,210,210,209,209,208,209,208,209,208,208,209,209,208,209,211,209,208,209,208,209,208,209,208,211,211,208,211,212,212,212,212,212,212,212,212,212,212,212,211,211,212,212,212,212,211,212,211,211,211,212,212,212,211,211,211,211,211,212,211,211,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,33,20,34,20,35,35,37,37,38,38,39,39,40,40,42,42,43,43,44,44,45,45,47,47,32,33,35,35,37,37,39,40,42,42,44,44,46,47,63,48,50,51,54,55,58,59,62,62,59,199,196,196,196,196,197,197,198,197,198,197,198,198,198,198,198,69,71,71,72,73,74,74,76,76,78,78,79,52,53,52,54,53,55,54,55,203,203,203,203,196,199,196,196,196,196,196,196,197,198,198,197,193,198,197,194,194,196,196,193,196,193,196,193,196,194,193,194,193,195,195,196,192,193,193,193,193,197,193,196,196,196,194,196,196,197,193,197,193,196,193,197,197,197,193,197,194,194,194,194,195,198,197,193,192,193,193,193,193,193,193,193,193,193,198,194,198,198,194,193,194,196,194,193,196,193,197,195,193,195,194,197,196,196,193,197,193,197,193,197,193,198,193,198,194,198,194,198,194,197,193,197,193,197,193,197,193,197,193,197,193,198,193,198,194,198,194,194 +,252,252,252,252,109,252,252,252,252,252,108,107,109,108,109,252,109,252,252,108,108,107,108,107,108,107,108,108,109,108,109,108,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,107,252,107,252,109,109,109,108,107,107,107,107,107,252,107,252,252,107,107,252,252,108,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,109,107,252,252,252,252,252,252,252,252,109,109,109,107,109,107,109,107,107,107,107,107,107,107,107,107,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,140,141,209,209,209,208,208,208,210,208,209,208,208,209,210,210,210,210,210,209,210,209,209,208,208,208,209,209,209,209,209,208,209,209,209,208,211,209,209,208,208,208,209,208,208,211,211,208,208,211,212,212,212,212,212,212,212,212,212,212,212,211,211,212,212,212,212,212,212,211,211,212,212,212,212,212,211,211,211,211,211,211,211,21,21,21,21,21,21,21,21,32,34,37,39,42,44,47,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,32,34,36,38,41,42,45,47,33,33,34,34,35,35,36,36,37,37,38,38,39,39,40,40,41,42,42,43,43,44,44,45,46,46,47,47,32,33,35,36,37,38,40,41,42,43,45,46,47,53,54,54,196,196,196,196,197,197,197,197,198,198,198,198,198,198,198,198,198,62,63,63,64,65,67,68,69,70,72,73,74,75,77,78,79,51,52,52,203,203,203,203,199,196,196,196,196,196,197,193,193,193,198,198,193,197,195,198,194,196,196,196,196,196,193,196,193,197,194,195,195,195,195,192,193,196,193,196,193,193,197,193,198,194,197,196,197,193,197,193,196,193,197,194,197,193,194,193,194,194,195,195,198,197,193,196,193,193,193,193,193,193,193,193,193,198,194,198,198,198,198,193,193,196,192,196,193,197,193,193,195,195,196,196,196,193,197,193,197,193,197,193,197,193,198,193,198,194,198,194,197,194,197,193,197,193,197,193,196,193,197,193,197,193,198,194,198,194,198,194 +,252,252,252,252,252,252,252,252,252,252,107,108,108,109,252,252,108,252,108,252,108,252,109,252,107,109,108,109,108,252,108,252,108,252,108,252,108,252,107,252,108,252,109,252,252,252,252,252,109,252,107,252,107,252,107,252,108,252,252,252,108,252,108,252,108,252,108,252,252,108,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,252,107,252,107,252,107,252,109,252,252,252,252,109,109,109,107,109,107,107,107,109,107,109,107,107,107,107,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,21,21,20,21,21,21,20,21,20,21,21,21,20,21,21,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,21,21,21,21,20,21,20,21,21,21,21,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,21,21,20,21,21,21,20,21,20,21,21,21,20,21,21,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,20,21,20,21,21,21,21,21,20,21,21,21,20,21,21,21,21,21,20,21,139,203,140,209,209,208,208,209,209,208,209,208,208,209,210,210,210,209,210,209,210,209,209,208,209,208,209,211,208,211,209,208,209,209,209,208,209,211,209,211,209,208,208,208,209,208,208,211,211,211,211,211,211,48,49,50,51,52,53,54,55,56,57,32,34,37,38,41,42,45,47,211,211,211,32,34,34,36,37,39,40,42,42,45,45,47,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,21,21,21,20,32,32,33,33,34,34,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48,49,49,50,50,196,196,196,196,197,196,197,197,198,197,198,198,198,198,198,198,198,198,198,60,199,192,196,62,63,64,65,65,67,67,69,69,71,199,196,72,203,203,203,203,199,196,196,196,196,196,193,193,198,197,198,197,198,197,195,197,198,194,196,196,196,196,193,196,194,197,194,197,195,195,195,192,193,196,193,193,193,193,197,197,196,194,198,196,196,193,197,197,196,193,197,194,197,193,197,197,194,194,195,195,198,198,194,197,196,197,193,197,193,197,193,197,193,198,194,198,198,194,198,198,193,194,193,196,193,197,193,197,195,197,195,196,197,193,197,193,197,193,197,193,197,193,198,193,198,194,198,194,198,193,197,193,197,193,197,193,197,193,197,193,198,193,198,193,198,194,198,198,198 +,252,252,252,252,109,252,252,252,252,252,252,108,108,108,109,108,252,252,252,252,252,252,252,252,108,107,108,108,108,108,108,108,252,108,109,108,252,252,252,107,252,252,252,252,252,252,252,252,252,252,252,107,252,107,108,107,252,252,252,252,252,252,108,108,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,109,107,109,107,252,252,252,252,252,252,252,252,109,107,109,107,109,107,107,107,107,107,109,107,107,107,21,21,21,21,20,21,21,21,21,21,21,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,21,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,21,21,21,21,21,21,20,21,21,21,21,21,21,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,21,21,21,21,21,21,20,21,21,21,21,21,21,21,21,21,21,21,20,21,21,21,21,21,21,20,21,21,21,40,20,48,50,51,54,55,57,59,61,63,63,139,61,62,208,48,209,209,208,208,209,50,51,210,210,210,210,210,209,209,209,209,208,208,208,209,208,208,208,211,211,209,209,209,209,208,208,208,208,211,211,209,208,208,208,208,208,208,208,211,211,205,211,205,32,34,36,37,40,41,43,45,47,32,33,34,35,36,37,38,40,41,42,42,211,211,211,211,211,211,211,211,21,21,21,21,21,21,21,32,37,42,47,21,21,21,21,21,21,21,32,35,38,41,44,47,21,21,21,21,32,46,21,21,21,21,21,21,32,34,37,39,42,44,47,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,32,33,33,34,34,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,48,49,49,49,196,196,196,196,196,197,197,197,197,198,197,198,198,197,198,198,198,198,198,192,196,196,197,197,61,62,63,63,64,65,66,66,199,196,196,196,196,196,196,196,196,196,196,198,198,197,193,193,197,198,198,198,198,198,197,195,195,196,196,196,196,197,197,197,197,195,195,195,197,195,195,193,196,193,196,193,196,193,193,196,193,197,198,196,196,197,193,196,193,197,193,197,197,197,193,198,194,195,195,194,195,194,197,196,196,193,197,193,197,193,197,197,197,194,198,194,197,198,198,198,193,196,196,193,197,197,197,195,195,195,196,196,193,197,196,197,193,197,197,197,193,197,197,197,193,198,198,198,194,197,197,197,193,197,196,196,193,197,197,197,193,198,198,198,194,198,198,194,198 +,252,252,252,252,252,252,252,252,252,108,252,108,108,109,108,109,108,252,108,252,252,252,108,252,107,109,107,109,108,252,108,109,108,252,108,252,108,252,108,252,108,252,108,252,252,252,107,252,107,252,109,108,107,252,107,252,107,252,108,252,108,252,108,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,252,107,252,107,252,107,252,107,252,252,252,109,252,252,109,107,109,107,109,107,107,107,109,107,109,107,109,107,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,21,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,21,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,21,32,21,34,21,36,20,38,21,41,43,43,20,36,47,36,57,58,59,60,62,63,63,63,209,49,130,130,130,48,210,210,210,210,209,210,209,210,209,209,208,209,208,209,208,208,211,211,208,209,211,209,208,209,208,209,208,209,208,209,209,209,208,208,208,209,208,209,208,211,211,208,211,211,21,215,215,215,215,213,212,215,215,211,214,213,215,212,213,213,213,213,211,211,211,211,212,211,211,211,21,211,21,39,47,21,21,20,21,21,21,21,21,21,21,20,21,21,21,21,21,21,21,20,21,21,21,21,21,21,21,20,21,21,21,21,21,21,21,20,21,21,21,21,21,21,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,32,32,33,33,34,34,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48,49,196,196,196,196,196,197,197,197,196,197,197,198,197,198,197,198,198,198,196,196,196,197,197,198,60,62,61,62,62,199,199,196,192,198,197,198,198,196,196,196,197,196,197,198,193,198,193,198,197,198,198,197,197,195,197,195,196,197,196,197,196,194,196,194,197,195,197,195,195,193,196,193,196,193,196,193,193,196,193,197,197,198,196,197,197,197,193,196,196,197,194,197,197,197,194,198,198,198,195,195,197,194,197,196,197,193,197,193,197,193,198,194,198,194,198,198,197,198,194,197,196,193,196,197,197,198,197,195,197,196,193,197,193,197,193,197,193,197,193,197,193,198,194,198,194,198,194,198,194,197,193,197,193,197,193,197,193,197,193,198,193,198,193,198,198,194,198,198 +,109,252,109,252,252,252,252,252,252,252,108,252,108,108,108,108,109,108,109,252,252,252,252,252,252,108,108,108,108,107,108,107,108,107,252,108,252,107,252,252,252,252,252,252,252,252,252,107,252,107,252,107,108,107,108,107,252,108,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,109,107,252,109,252,252,252,252,252,252,252,252,109,107,109,107,109,107,107,107,109,107,109,107,107,21,21,21,20,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,20,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,21,21,21,20,21,21,20,21,21,20,21,21,21,21,21,21,21,21,45,21,36,20,37,21,38,38,59,60,62,63,62,32,36,40,43,47,210,210,54,210,210,209,210,209,209,209,209,208,208,208,208,208,208,211,211,211,211,208,211,211,32,33,34,35,35,37,37,38,39,40,41,42,42,44,44,45,46,47,212,215,215,215,213,21,212,21,32,39,46,21,213,213,215,205,214,213,214,21,211,211,213,32,211,39,43,47,47,21,21,21,21,21,21,21,21,21,32,35,38,41,44,47,21,32,37,42,47,44,44,44,44,44,44,44,44,44,44,44,32,36,39,43,47,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,32,32,32,32,33,33,33,34,34,34,35,35,36,36,37,37,37,38,38,39,39,39,40,40,41,41,42,42,43,43,43,44,44,44,45,45,46,46,47,47,48,48,49,49,196,196,196,196,197,196,196,197,197,198,197,197,198,198,198,197,198,198,197,196,196,196,197,197,198,60,61,61,199,192,196,192,197,197,197,197,198,198,198,198,196,197,198,198,198,197,197,197,198,198,198,197,195,197,195,195,194,197,198,198,197,197,197,197,195,197,195,195,195,196,193,196,193,193,193,196,193,196,197,194,198,196,197,196,197,193,196,193,197,194,197,197,198,194,198,194,198,195,195,195,197,196,193,197,196,197,193,197,197,197,194,198,198,198,198,198,198,198,198,197,196,196,193,197,197,198,198,197,196,196,196,196,196,196,197,197,197,197,197,197,197,197,198,197,198,196,198,198,198,197,197,196,196,196,197,197,197,197,197,197,198,198,198,194,198,198,198,194 +,252,109,252,252,252,252,252,252,252,252,252,108,252,252,252,109,108,252,108,252,108,252,109,252,109,108,108,109,108,109,108,252,108,252,108,252,108,252,108,252,108,252,108,109,108,252,252,252,252,252,108,108,108,108,107,252,107,252,108,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,252,107,252,107,252,107,252,109,252,109,252,252,252,252,252,252,109,107,109,107,107,107,109,107,109,107,109,107,107,21,40,21,41,21,21,21,43,21,44,21,45,21,21,21,32,21,34,21,36,21,21,21,39,21,32,21,35,21,21,21,39,21,41,21,43,21,21,21,47,21,46,21,34,21,21,21,35,21,38,21,41,21,21,21,46,21,32,21,20,21,21,21,32,21,35,21,38,21,21,21,44,21,47,21,36,21,21,21,37,21,38,21,38,21,21,21,39,21,40,21,41,21,21,21,47,21,42,21,34,21,21,21,38,21,40,21,43,21,21,21,47,21,33,21,35,21,21,21,39,21,41,21,43,21,21,21,46,21,37,21,37,21,21,21,38,21,38,21,20,21,21,21,39,21,42,21,45,32,34,35,37,38,40,41,43,44,46,47,210,210,52,52,209,55,57,210,209,210,209,209,208,209,208,208,208,208,208,208,211,211,211,211,208,211,208,208,21,209,215,208,215,213,214,215,21,214,215,212,211,211,211,211,211,37,40,41,44,45,47,213,215,213,215,32,34,35,37,38,40,41,213,211,211,213,211,211,21,211,21,21,21,21,21,32,37,41,47,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,45,45,45,45,45,45,45,45,45,32,35,40,43,47,32,33,32,33,32,32,32,33,33,34,33,34,34,35,35,36,35,36,36,37,37,38,37,39,38,39,39,40,39,41,40,41,41,42,42,43,42,43,43,44,44,45,44,45,45,46,46,47,46,47,48,49,48,49,49,50,50,196,196,196,196,196,196,197,197,198,198,198,197,198,198,198,197,198,198,197,196,197,197,198,197,198,60,192,192,196,192,197,196,197,197,198,197,198,198,198,196,197,197,198,198,198,197,198,197,198,197,198,197,195,195,195,196,198,197,198,196,197,197,195,197,195,195,195,193,193,196,193,197,193,197,193,196,197,197,198,198,196,196,198,197,198,196,196,196,197,197,197,197,198,198,198,198,195,195,194,196,194,197,193,197,193,197,197,198,197,198,194,198,198,197,198,197,198,198,197,196,193,196,197,197,198,198,197,196,196,193,197,193,197,193,197,193,197,193,198,194,198,194,198,193,198,194,198,198,197,193,196,193,197,193,197,193,197,193,198,193,198,194,198,198,198,198,198 +,109,252,109,252,252,252,252,252,252,252,108,252,108,252,108,108,109,108,109,108,252,252,252,252,252,108,108,108,108,108,108,108,109,108,108,108,252,108,252,108,252,252,108,108,252,109,252,252,252,252,109,108,108,108,108,108,252,252,252,252,252,252,108,108,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,252,109,252,109,252,252,252,252,252,252,252,252,109,107,109,107,109,107,107,107,109,109,109,109,109,107,21,21,41,20,21,21,43,21,21,20,45,21,21,21,35,20,21,21,39,21,21,21,34,21,21,21,42,21,21,21,45,21,21,21,39,21,21,21,32,20,21,21,41,21,21,20,33,21,21,21,36,21,21,21,39,21,21,21,33,21,21,21,33,20,21,21,36,21,21,20,38,21,21,21,41,21,21,21,44,21,21,20,47,21,21,21,47,21,21,21,46,21,20,21,45,21,21,21,43,20,21,21,43,21,21,20,44,21,21,21,34,20,21,21,38,21,21,21,41,21,21,21,45,20,21,21,32,21,21,20,32,21,21,21,36,21,21,21,40,21,21,20,33,21,21,34,36,36,37,38,39,39,40,41,42,43,44,44,48,49,50,51,53,54,55,56,57,58,60,60,62,63,48,49,51,51,53,54,55,56,32,33,34,35,215,215,215,215,211,211,215,215,215,215,215,215,215,215,215,215,215,212,215,213,46,46,46,46,46,46,46,46,32,212,21,215,213,214,46,46,46,46,46,46,46,46,46,46,47,21,21,21,21,21,21,47,47,47,46,46,46,46,46,46,46,46,46,46,47,47,47,47,47,32,32,32,32,32,33,33,33,33,33,33,33,32,33,33,33,33,34,34,34,34,35,35,35,35,36,36,36,36,37,37,38,38,38,38,39,39,40,40,40,40,41,41,41,41,42,42,42,42,43,43,44,44,44,44,45,45,45,46,46,46,47,47,47,48,49,49,49,49,50,50,51,51,52,196,196,196,197,196,196,196,197,197,198,197,198,198,197,197,198,197,198,193,197,197,197,197,198,198,198,192,196,192,196,196,197,197,197,197,198,198,198,196,197,197,198,198,198,197,197,197,195,195,197,197,196,197,197,197,198,198,198,198,197,197,197,197,195,197,195,197,196,196,196,193,197,197,196,196,197,194,198,197,198,196,196,197,198,193,197,194,197,196,197,197,198,197,198,195,198,198,198,197,196,196,196,197,196,197,197,197,197,198,197,198,198,197,198,197,198,198,198,197,193,196,193,197,198,198,197,196,196,196,196,196,197,197,197,197,197,197,197,197,197,197,197,197,196,198,198,198,198,197,196,196,197,196,197,197,197,197,197,197,198,198,198,194,198,194,198,198 +,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,108,109,108,109,108,252,108,252,252,108,108,108,108,109,108,109,108,252,108,252,108,252,108,252,108,108,108,108,108,252,108,252,108,252,108,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,107,107,107,252,107,252,107,252,107,252,109,252,109,252,252,252,252,252,252,109,107,109,107,109,107,107,107,109,107,109,107,109,107,37,21,41,21,44,21,32,21,42,21,46,21,32,21,37,21,42,21,32,21,33,21,35,21,35,21,37,21,37,21,39,21,40,21,41,21,42,21,43,21,44,21,45,21,46,21,47,21,39,21,41,21,42,21,44,21,45,21,32,21,42,21,43,21,33,21,32,21,32,21,47,21,36,21,38,21,39,21,41,21,42,21,43,21,45,21,46,21,47,21,32,21,33,21,34,21,35,21,36,21,37,21,38,21,38,21,39,21,40,21,41,21,42,21,47,21,43,21,44,21,32,21,35,21,37,21,47,21,41,21,40,21,45,21,47,21,41,21,42,21,44,21,45,21,47,21,40,21,32,21,41,203,203,202,42,39,40,40,41,41,42,42,43,42,44,44,45,44,45,45,47,209,41,209,21,209,32,46,21,209,21,208,21,209,215,215,215,215,47,208,32,34,37,39,42,44,47,212,21,211,21,47,21,215,215,213,213,215,47,47,47,47,47,47,47,47,47,47,45,46,21,211,21,211,21,21,47,47,47,47,47,47,47,47,33,32,33,32,33,32,33,32,33,32,33,33,34,33,34,33,34,33,34,34,34,32,33,32,33,33,34,33,35,34,35,35,36,35,36,36,37,36,37,37,38,37,38,38,39,39,40,39,40,40,41,41,42,41,42,42,43,42,43,43,44,43,44,44,45,45,46,45,46,46,47,46,47,100,101,101,102,102,48,48,49,49,50,49,51,50,51,51,199,196,53,52,53,196,196,196,197,196,197,197,198,198,198,198,197,196,197,197,198,197,198,197,198,196,197,197,198,198,197,193,192,196,197,196,197,196,197,197,198,197,198,196,197,197,198,195,195,197,195,195,197,197,197,197,198,197,198,197,198,197,198,197,198,197,198,195,197,195,197,196,196,196,197,197,196,196,197,197,197,197,198,196,196,198,198,198,196,196,197,197,197,197,197,197,198,198,198,195,195,195,198,196,196,197,193,197,196,197,197,198,194,198,194,197,198,197,198,198,198,198,197,197,196,196,197,197,198,196,196,196,197,193,197,196,197,193,197,197,197,194,197,197,198,194,196,197,198,197,196,198,197,193,196,196,197,193,197,197,197,193,198,197,198,193,198,194,198,197,197 +,252,252,109,252,252,252,252,252,252,252,108,252,108,252,108,252,252,108,109,252,109,252,252,252,252,252,108,108,108,108,108,108,108,108,108,108,109,108,252,108,108,108,108,108,108,108,252,108,252,108,252,252,108,108,252,108,252,108,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,109,107,252,109,252,252,252,252,252,252,252,252,252,252,109,107,109,107,109,107,107,109,109,107,109,107,107,36,37,37,39,39,32,21,34,34,35,36,37,38,39,21,40,41,42,43,44,44,45,21,35,37,40,42,45,32,33,21,36,37,38,39,41,42,43,21,46,47,40,32,34,35,37,21,40,41,32,34,36,38,41,21,45,47,40,41,41,41,42,21,43,43,43,43,44,44,45,21,32,34,41,37,45,40,44,21,32,47,36,37,40,38,43,21,47,41,38,32,40,33,43,21,46,34,38,35,40,36,42,21,44,38,45,39,47,40,37,21,39,41,40,33,41,32,43,21,44,44,45,32,47,37,33,21,34,47,35,34,36,32,37,21,38,42,39,47,32,47,33,21,35,39,36,40,37,40,38,21,39,210,34,203,202,203,202,203,203,210,202,203,202,203,202,203,36,203,37,204,203,202,203,203,21,203,203,204,203,204,204,204,215,215,21,209,21,213,215,214,21,215,213,215,215,212,215,215,215,32,32,32,32,32,32,32,33,32,33,214,33,33,33,215,214,214,213,214,33,33,33,33,34,33,34,34,34,34,34,34,34,34,34,34,34,34,35,34,35,35,35,35,35,35,35,35,32,32,33,33,33,33,34,34,34,34,35,196,197,197,36,36,37,37,37,37,38,38,38,38,39,39,40,40,40,40,41,41,41,41,42,42,43,43,43,43,44,44,44,44,45,45,45,45,46,46,47,47,47,97,98,98,99,99,100,100,101,48,48,49,49,49,50,50,51,51,51,52,52,52,53,192,196,196,196,198,196,196,197,196,196,196,197,197,198,198,197,197,198,198,196,198,197,197,197,197,198,198,198,198,198,198,192,196,192,196,196,196,196,197,198,197,197,197,198,197,198,195,195,197,195,195,197,197,197,197,197,197,197,197,198,198,198,198,198,198,198,196,196,196,197,196,196,196,196,196,196,196,197,196,198,197,198,198,197,196,198,198,196,196,197,196,197,196,197,197,198,197,198,198,198,198,198,198,197,196,196,197,197,197,197,197,197,198,197,197,197,197,198,197,198,198,198,198,197,196,197,197,198,196,196,196,196,196,197,196,197,197,197,197,197,197,197,197,197,197,198,196,197,197,198,196,198,197,196,196,196,196,197,197,197,197,197,197,198,197,198,194,198,198,198,197 +,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,108,109,108,252,108,252,109,252,109,108,109,108,108,109,108,252,108,109,108,252,108,108,108,108,108,252,108,252,108,252,108,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,108,107,109,107,252,107,252,107,252,107,252,109,252,109,252,252,252,252,252,252,109,107,109,107,109,107,109,107,109,107,109,107,36,21,37,21,39,21,40,21,42,21,43,21,45,21,32,21,36,21,39,21,42,21,46,21,38,21,32,21,34,21,36,21,39,21,42,21,32,21,34,21,36,21,38,21,33,21,35,21,36,21,43,21,40,21,42,21,44,21,46,21,47,21,42,21,43,21,32,21,37,21,42,21,47,21,32,21,34,21,35,21,36,21,37,21,38,21,40,21,46,21,35,21,32,21,33,21,36,21,43,21,36,21,37,21,38,21,39,21,40,21,41,21,42,21,42,21,43,21,44,21,45,21,46,21,47,21,32,21,32,21,32,21,34,21,35,21,37,21,38,21,40,21,41,21,43,21,44,21,46,21,47,21,32,21,32,21,32,38,32,39,32,40,32,42,32,43,32,44,32,45,32,46,32,38,32,34,32,37,32,41,32,45,32,46,32,40,32,41,32,41,32,42,32,35,36,35,36,35,36,35,36,35,36,36,36,36,36,36,36,36,36,36,37,36,37,36,37,36,37,36,37,36,37,36,37,36,37,36,37,36,37,36,37,32,33,32,33,33,34,33,34,34,35,34,35,35,36,35,36,36,37,36,37,37,38,37,196,196,197,197,198,197,197,197,198,40,41,40,41,41,42,41,42,42,43,42,43,43,44,43,44,44,45,44,45,45,46,45,46,46,47,46,47,47,101,101,102,102,96,96,97,97,48,48,49,49,50,50,51,51,52,51,199,199,196,196,196,196,198,198,56,199,196,196,197,197,198,196,197,196,197,196,197,197,198,198,197,197,198,198,198,193,199,199,197,196,197,197,198,197,198,198,198,196,196,196,196,196,196,197,198,197,197,197,198,197,198,197,195,195,195,197,197,197,197,197,198,197,198,197,198,197,198,198,198,197,198,196,196,196,197,197,198,197,198,197,198,196,196,197,197,197,198,198,196,196,196,198,198,197,196,196,196,196,197,197,197,197,198,198,198,198,198,197,198,197,196,196,197,196,197,197,197,196,197,197,198,197,198,197,198,197,198,198,198,197,196,196,198,198,196,196,197,193,197,196,197,193,197,196,197,193,197,197,198,194,198,196,197,194,198,198,196,198,197,196,197,193,197,196,197,193,197,197,198,193,198,197,198,197,198,197,197 +,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,108,109,252,109,108,252,252,252,252,108,252,108,109,108,108,108,108,252,108,108,108,108,108,108,108,108,108,108,108,252,108,252,108,252,252,108,108,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,109,107,109,107,252,109,252,109,252,252,252,252,252,252,252,107,109,107,109,107,109,107,109,107,109,107,107,35,33,36,35,37,37,39,39,40,41,41,43,42,45,44,47,45,32,33,34,34,35,36,37,37,38,39,40,40,41,42,43,43,44,45,46,46,47,34,40,35,41,41,42,47,44,36,45,37,46,37,47,32,39,36,41,39,43,43,45,47,47,32,38,33,32,35,34,36,37,38,40,34,42,39,44,44,47,34,36,35,37,33,39,36,40,39,41,41,43,44,44,47,45,44,46,45,34,46,35,36,36,32,37,38,38,44,39,34,41,38,42,41,43,45,44,44,45,45,46,46,47,32,35,40,36,41,36,32,36,39,40,38,40,39,42,40,32,41,37,32,42,44,47,33,44,36,42,39,42,42,47,45,46,44,46,44,46,45,46,32,46,33,46,33,32,34,32,34,32,35,32,32,32,35,32,204,203,41,32,209,203,204,215,215,40,35,35,213,36,213,36,35,214,214,215,215,36,212,215,212,36,36,36,36,36,212,36,213,214,213,214,214,37,36,36,36,37,32,32,211,33,211,33,214,34,34,34,34,35,35,35,35,36,36,36,36,37,37,37,37,37,37,38,38,38,38,39,39,39,39,40,40,40,197,197,197,197,197,198,198,198,198,198,198,198,198,198,43,44,44,44,44,45,45,45,45,46,46,46,46,47,47,47,47,97,97,98,98,99,99,100,100,101,48,48,49,49,50,50,50,51,51,52,52,53,53,54,54,55,199,192,196,196,196,196,197,198,198,198,199,196,196,196,196,198,198,198,196,197,196,196,197,197,198,198,197,198,198,198,197,199,199,196,196,198,198,197,197,198,198,198,197,196,196,196,196,196,197,198,198,198,197,197,197,198,198,198,198,197,197,197,197,197,198,197,197,198,197,198,197,198,198,198,198,198,196,196,196,197,197,197,197,198,198,198,197,196,196,197,198,197,197,196,196,197,196,198,198,198,196,197,196,197,196,197,197,198,197,198,198,198,198,198,198,197,196,196,196,197,196,197,196,197,197,197,197,197,197,198,197,198,198,198,198,198,197,197,197,196,196,196,196,197,196,197,196,197,197,197,197,197,197,197,197,198,196,196,197,197,198,198,197,198,197,196,196,197,196,197,197,197,197,197,197,198,198,198,198,198,198,197,197 +,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,108,109,108,109,252,252,252,252,252,108,109,108,109,252,108,252,108,252,108,108,108,109,108,108,108,252,108,252,108,252,108,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,252,252,252,109,252,252,252,252,252,252,252,252,252,109,107,107,107,107,252,107,252,107,252,107,252,109,252,109,252,252,252,252,252,107,109,107,109,107,109,107,109,107,107,107,107,21,41,21,41,21,41,21,33,21,35,21,36,21,38,21,39,21,41,21,43,21,44,21,46,21,47,21,34,21,37,21,39,21,42,21,45,21,47,21,41,21,41,21,41,21,41,21,41,21,41,21,41,21,41,21,41,21,41,21,41,21,41,21,41,21,36,21,43,21,41,21,41,21,33,21,34,21,35,21,36,21,37,21,38,21,39,21,40,21,41,21,41,21,43,21,43,21,45,21,45,21,47,21,47,21,47,21,32,21,37,21,41,21,45,21,47,21,36,21,36,21,36,21,36,21,37,21,37,21,37,21,42,21,47,21,47,21,35,21,41,21,47,21,47,21,47,21,47,42,32,43,32,44,32,44,32,45,32,45,32,46,32,47,32,47,40,37,40,38,47,39,47,32,47,33,32,34,47,35,32,36,32,37,32,38,35,35,35,34,35,34,35,34,35,35,35,36,37,36,36,36,37,36,32,32,33,32,33,33,34,33,34,34,35,34,35,34,35,35,36,35,36,36,37,36,37,36,37,37,38,37,38,38,39,38,39,39,40,39,40,40,41,40,41,41,42,41,42,41,42,42,197,196,197,196,197,197,198,197,198,197,198,197,198,198,198,197,198,46,47,46,47,47,47,102,103,96,97,98,99,100,101,102,96,96,48,48,49,49,50,50,51,51,52,52,53,53,54,53,55,55,56,55,56,56,58,196,192,196,196,196,196,197,198,197,198,198,198,192,196,196,196,196,197,197,198,197,198,196,196,196,197,197,198,198,198,197,198,198,199,196,196,196,197,197,198,198,198,197,197,198,197,196,197,196,196,197,197,197,198,197,198,197,197,197,198,197,198,197,197,197,197,198,198,197,198,197,198,197,198,198,198,198,198,198,196,196,197,197,198,197,198,197,198,197,196,196,197,198,198,197,196,196,197,197,198,197,198,198,198,196,197,197,197,197,198,198,198,198,198,198,198,197,198,196,197,196,197,196,197,196,197,197,197,197,197,197,198,197,198,197,198,197,198,198,198,197,196,196,197,196,197,196,197,196,197,196,197,193,197,197,198,197,198,197,196,193,197,197,198,198,197,198,197,193,196,196,197,196,197,197,198,193,198,197,198,197,198,197,197,197,197 +,252,252,109,252,252,252,108,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,109,252,252,109,252,252,108,252,108,252,108,252,108,108,108,108,108,108,108,108,108,108,108,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,109,107,109,109,252,109,252,252,252,252,252,252,252,252,252,107,109,107,109,107,109,107,109,107,107,107,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,32,21,36,21,40,21,43,21,47,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,32,21,42,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,44,21,32,33,34,21,36,21,37,21,39,21,41,21,43,21,44,21,46,21,47,21,32,21,32,21,32,21,32,21,32,21,32,21,32,44,32,46,36,44,36,45,36,45,36,46,36,47,34,203,46,46,47,47,47,40,47,203,47,203,47,34,34,34,35,34,35,34,35,34,35,34,35,32,32,32,33,33,33,33,33,33,34,34,34,34,35,35,35,35,35,35,36,36,36,36,36,36,37,37,37,37,38,38,38,38,38,38,39,39,39,39,39,39,40,40,40,40,41,41,41,41,41,41,42,42,42,42,43,42,43,43,43,43,44,44,44,196,197,197,197,197,197,197,197,197,198,197,198,198,198,198,198,197,198,198,198,101,101,102,102,102,103,103,96,48,49,49,50,50,51,51,52,52,53,53,53,54,54,55,55,56,56,57,57,58,58,59,59,59,196,196,196,192,196,196,197,197,197,197,197,197,198,198,196,196,196,196,196,197,198,198,197,197,198,198,198,198,197,197,197,198,198,198,198,198,196,196,196,196,197,197,197,198,198,197,198,197,196,196,197,197,198,197,197,198,198,198,198,198,197,197,197,198,198,197,198,197,197,197,198,198,197,197,197,197,198,198,198,198,198,198,196,196,197,197,197,198,198,196,196,196,196,197,198,198,198,197,196,196,197,197,197,197,198,197,198,197,198,198,197,197,197,197,198,197,198,198,198,198,198,197,196,196,196,196,197,196,197,197,197,197,197,197,197,197,198,198,198,198,198,197,197,197,198,196,196,196,196,196,197,196,197,197,197,197,197,197,197,197,197,197,197,196,197,197,197,197,198,197,198,197,196,196,196,196,197,197,197,197,197,197,198,198,198,198,197,197,197,198 +,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,108,252,108,252,252,252,108,108,108,108,252,108,109,108,252,108,252,108,252,108,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,252,107,252,107,252,107,252,107,252,109,252,109,252,252,252,252,109,107,109,107,109,107,109,107,109,107,107,34,32,35,32,37,32,38,32,39,32,41,32,42,32,32,32,33,32,34,32,36,32,37,32,38,32,39,32,40,32,41,32,32,32,34,32,35,32,37,32,38,32,40,32,41,32,43,32,44,32,46,32,36,32,38,32,40,32,42,32,44,32,47,32,39,32,42,32,45,32,32,32,46,32,35,32,36,32,37,32,38,32,39,32,35,32,41,32,46,32,35,32,36,32,32,32,33,32,34,32,32,32,32,32,33,34,34,36,35,39,35,42,36,45,37,47,38,32,38,32,21,32,21,32,21,32,21,32,21,32,21,32,21,47,21,46,21,47,21,46,21,40,21,40,21,40,46,40,37,42,38,40,39,40,32,40,32,40,39,40,46,35,35,35,35,35,35,35,35,35,35,35,35,32,32,33,32,33,33,34,33,34,33,34,34,35,34,35,34,35,35,36,35,36,36,37,36,37,36,37,215,38,37,38,37,38,38,212,38,39,39,215,39,212,39,40,211,41,40,41,40,41,42,42,42,42,42,43,42,43,42,43,43,44,43,44,43,44,44,45,44,45,45,46,45,46,45,197,196,197,196,197,197,197,197,198,197,198,197,198,197,198,198,198,197,198,197,198,198,198,48,49,49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59,60,60,61,61,62,196,196,196,196,196,196,196,196,196,197,196,198,197,198,198,196,196,196,196,196,196,198,197,198,197,198,197,198,197,198,197,198,198,197,197,198,198,198,198,196,196,197,196,196,196,197,197,198,197,198,197,198,197,198,196,197,197,198,198,198,197,198,197,198,197,197,197,198,198,198,197,197,197,197,198,198,197,198,197,198,197,198,197,198,198,196,196,197,197,198,197,196,196,196,196,197,197,198,197,198,197,196,196,197,196,197,197,197,197,198,197,198,198,197,196,197,197,198,197,198,197,198,198,198,197,196,196,197,196,197,196,196,196,197,197,198,198,198,197,198,198,198,197,198,197,198,196,196,196,197,196,197,196,197,196,197,196,197,196,197,197,197,197,198,197,198,197,196,196,197,197,198,198,198,198,197,196,197,196,197,196,197,197,198,197,198,197,198,198,197,198,197,197,197 +,109,252,109,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,252,108,252,108,109,108,108,108,108,108,108,108,108,108,108,252,108,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,107,107,252,109,252,109,252,252,252,252,252,252,252,252,252,252,109,107,109,107,109,107,109,107,107,107,107,34,35,34,35,35,35,36,35,36,35,37,35,38,35,38,35,39,35,40,35,40,35,41,35,42,35,42,35,43,35,44,35,45,35,45,35,46,35,46,35,41,36,41,36,42,36,42,36,43,36,43,36,44,36,44,36,32,36,36,36,40,36,45,36,40,36,43,36,46,36,36,36,37,36,37,36,38,36,39,36,40,36,46,36,32,36,32,36,33,36,33,36,34,36,34,36,35,36,35,36,32,36,34,36,37,36,32,36,33,36,34,36,35,45,36,40,37,40,38,40,39,40,32,40,34,40,35,40,21,40,21,32,39,32,41,32,42,32,43,47,45,47,46,47,33,47,34,47,35,43,37,43,33,43,35,43,37,43,39,33,35,32,32,33,33,33,33,33,33,34,33,34,34,34,34,35,35,35,35,36,36,36,203,36,36,37,36,204,37,37,37,38,215,38,215,39,39,39,39,39,39,40,39,40,40,40,40,41,41,41,41,42,42,42,42,42,42,43,43,43,43,43,43,44,44,44,44,45,45,45,197,45,45,46,46,46,46,46,46,47,47,47,99,197,196,197,196,197,197,197,197,197,197,197,197,198,197,198,197,198,198,198,198,198,198,198,198,198,198,198,53,54,54,55,55,56,57,57,57,58,59,59,60,61,61,61,62,63,63,64,64,66,66,196,196,196,196,196,196,196,196,196,197,198,196,197,197,198,198,197,197,196,196,196,196,197,196,197,197,198,197,198,198,198,197,197,197,198,198,198,198,198,198,198,198,198,196,196,196,197,197,197,197,198,197,198,198,198,198,198,198,198,196,197,198,198,197,197,197,199,196,197,197,198,197,197,197,198,198,198,198,198,197,197,197,198,198,198,198,198,198,198,196,196,197,197,197,196,196,197,196,197,197,198,198,198,197,197,196,196,196,197,197,197,197,197,197,198,198,198,197,197,197,197,197,198,198,198,198,198,198,196,196,197,197,197,197,197,197,198,197,198,198,198,197,198,197,197,196,196,196,196,196,196,198,196,196,196,196,196,196,197,197,197,197,197,197,197,197,197,197,197,197,198,196,196,197,197,198,198,197,198,197,196,196,197,196,197,197,197,197,197,197,198,198,198,198,196,197,198,197 +,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,108,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,109,108,108,252,108,108,108,252,108,109,108,252,108,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,252,107,252,107,252,107,252,107,252,107,252,252,252,109,252,252,252,107,109,107,109,107,109,107,109,107,107,107,38,34,38,35,38,35,38,36,38,37,38,38,38,38,38,39,38,40,38,40,38,41,38,42,38,42,38,43,38,44,38,45,38,45,38,46,38,47,38,39,40,39,40,39,40,39,40,40,40,40,40,41,40,32,40,33,40,34,40,36,40,37,40,38,40,39,40,41,40,42,40,43,40,45,40,46,40,44,40,46,40,43,40,45,40,32,40,33,40,33,40,34,40,35,40,32,40,32,40,33,40,34,40,35,40,32,40,33,40,34,40,36,40,32,40,33,44,35,44,37,44,33,44,36,45,39,45,42,45,45,40,37,40,38,40,40,40,41,40,42,32,43,32,44,32,45,32,47,32,32,47,34,47,35,47,36,47,37,47,39,34,34,35,36,38,38,40,40,42,42,44,45,46,47,35,35,32,35,38,41,44,46,37,37,37,37,38,37,38,38,39,38,39,39,40,39,40,39,40,40,41,40,41,41,42,41,42,42,43,42,43,43,44,43,44,44,45,44,45,45,46,45,46,46,47,46,47,47,197,197,198,198,97,96,98,97,98,98,99,197,198,197,198,198,198,196,197,197,197,197,197,197,198,197,198,197,198,197,198,198,198,198,198,197,198,197,198,198,198,198,59,59,60,60,61,61,62,62,63,89,90,89,90,90,91,64,66,66,69,69,196,196,196,196,196,196,196,196,198,197,198,197,198,197,196,197,198,197,198,197,196,196,197,196,197,196,197,197,198,197,198,197,198,198,198,197,198,197,198,197,198,198,198,198,198,196,196,196,197,196,197,197,197,198,197,197,198,198,198,197,198,198,198,197,198,197,198,199,199,196,193,197,197,197,198,197,197,197,198,197,198,198,198,197,198,197,198,197,198,198,198,196,196,196,197,197,196,196,197,196,197,197,198,197,198,198,198,196,196,196,197,196,197,197,198,197,198,198,198,196,197,197,198,197,198,197,198,197,198,198,198,196,197,196,197,197,198,197,198,197,198,197,198,196,196,196,196,196,196,196,196,196,198,198,196,196,197,197,198,196,197,196,197,196,197,196,197,196,197,197,198,197,198,197,196,196,197,197,198,198,198,198,198,196,196,196,197,196,197,197,198,197,198,197,198,198,196,197,198,197,198 +,109,252,108,252,108,252,108,252,108,252,108,252,252,252,252,108,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,108,108,108,108,108,108,108,108,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,107,252,109,252,109,252,252,252,252,252,252,252,252,107,107,109,107,109,107,109,107,109,107,107,107,41,35,41,35,41,36,41,37,41,38,41,39,41,39,41,40,41,41,41,42,41,43,41,43,41,44,41,45,41,46,41,46,41,39,41,40,41,42,41,43,43,45,43,46,43,39,43,39,43,39,43,32,43,33,43,33,43,34,43,35,43,36,43,37,43,38,43,38,43,39,43,40,43,41,43,42,43,42,43,43,43,44,43,45,43,46,43,46,43,45,43,45,43,45,43,45,43,46,43,46,43,46,43,47,43,47,43,32,43,34,43,35,43,36,32,32,34,33,35,34,37,35,39,36,40,37,42,37,44,38,45,39,47,40,47,41,47,32,46,35,46,38,32,41,32,44,32,47,32,34,32,35,32,36,32,37,32,38,32,38,32,39,32,40,32,41,32,42,32,43,32,32,33,33,33,33,34,34,35,32,33,34,35,35,37,37,38,39,40,41,42,42,44,44,45,46,47,42,43,213,44,44,44,44,45,45,46,46,47,47,98,98,99,99,214,99,100,214,100,100,101,101,101,101,101,196,197,197,197,197,198,198,103,103,197,197,197,197,197,197,197,197,197,197,198,197,198,197,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,128,128,129,130,130,88,88,89,89,89,89,89,89,90,64,66,68,70,72,75,77,79,50,196,196,196,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,197,198,198,198,198,198,197,198,198,198,198,198,198,198,198,196,196,197,198,196,197,197,197,197,198,197,198,197,198,198,198,198,196,196,196,199,199,196,196,197,196,197,197,198,194,198,198,197,197,198,198,198,197,197,197,198,198,198,198,198,196,196,196,197,197,197,196,196,196,196,197,197,197,198,198,198,196,196,196,197,197,197,197,197,197,198,198,198,197,197,197,197,197,198,197,198,198,198,198,198,198,197,197,197,197,198,197,198,198,198,196,196,196,196,196,196,196,196,196,197,197,198,196,196,197,197,197,198,198,196,196,196,196,197,197,197,197,197,197,197,197,197,197,196,196,197,197,197,198,198,197,198,197,196,196,196,196,197,197,197,197,198,198,198,198,196,197,197,197,198,198 +,252,109,252,108,252,108,252,252,252,252,252,252,252,252,252,108,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,108,108,108,252,108,252,108,252,108,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,252,107,252,107,252,107,252,107,252,109,252,252,252,252,252,107,109,107,109,107,109,107,107,107,107,107,107,32,44,33,44,34,44,35,44,36,44,37,44,38,44,39,44,41,44,42,44,43,44,44,44,45,44,46,44,44,44,46,44,37,44,38,44,39,44,40,47,41,47,42,47,43,47,44,47,45,47,46,47,32,47,32,47,33,47,34,47,35,47,35,47,36,47,37,47,37,47,38,47,39,47,39,47,40,47,41,47,42,47,42,47,43,47,44,47,45,47,45,47,46,47,47,47,36,47,37,47,38,47,38,47,39,47,40,47,34,47,39,47,44,47,32,47,33,47,34,47,35,47,35,32,36,32,37,32,38,32,39,32,40,32,41,32,32,32,33,32,35,36,36,36,38,36,39,36,41,36,42,36,44,36,45,36,47,36,37,36,38,36,38,36,39,36,40,36,41,36,41,32,42,32,43,32,44,32,45,32,32,33,33,34,34,35,34,36,35,37,36,38,37,39,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,99,99,100,99,100,100,101,100,101,196,197,196,197,196,197,197,198,197,198,197,198,197,198,197,197,197,198,197,198,197,198,197,198,197,198,197,198,197,198,197,198,198,198,198,134,134,136,136,138,139,141,143,143,198,128,129,129,130,64,66,68,69,72,73,76,77,79,64,67,69,72,74,77,79,79,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,198,198,198,198,198,198,198,198,198,198,198,198,198,197,198,197,198,198,196,198,198,198,198,198,197,196,197,197,197,198,197,197,197,197,197,197,198,197,198,198,198,198,197,197,199,196,196,196,196,196,197,197,198,197,198,197,198,197,198,197,198,198,197,197,198,197,198,198,198,198,196,196,197,196,197,196,197,196,196,197,198,197,198,197,198,197,196,196,197,196,197,197,198,197,198,197,198,196,197,197,197,197,198,197,198,197,198,198,198,197,198,196,197,197,198,197,198,198,198,196,196,196,196,196,196,196,197,196,197,197,198,196,197,196,197,197,198,197,198,196,197,196,197,196,197,196,197,196,197,197,197,197,198,196,197,196,197,197,198,198,198,198,196,196,197,196,197,196,197,197,198,197,198,197,196,197,197,197,198,198,198 +,109,252,108,252,108,252,108,252,252,252,108,252,252,252,252,252,108,108,108,108,109,252,109,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,108,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,107,107,107,107,252,252,252,252,252,252,252,252,252,107,107,107,109,107,109,107,109,107,109,107,107,107,107,32,47,33,47,33,47,33,47,33,47,34,47,32,47,34,47,35,47,36,47,37,47,39,47,40,47,41,47,42,47,44,47,45,47,46,47,39,47,40,32,40,32,41,32,42,32,43,32,43,32,44,32,45,32,46,32,32,32,33,32,34,32,35,32,36,32,37,32,37,32,39,32,39,32,40,32,41,32,42,32,43,32,44,32,45,32,46,32,47,32,32,32,34,32,35,32,37,32,39,32,41,32,43,32,44,32,46,32,43,32,45,32,46,32,33,32,33,32,35,32,35,36,37,36,37,36,39,36,40,36,41,36,42,37,43,37,32,37,33,37,34,40,35,40,36,40,37,39,38,40,39,40,40,40,42,39,43,40,44,40,45,40,46,39,47,40,39,40,39,40,40,37,41,37,42,37,42,37,43,32,44,32,45,32,45,32,46,32,38,32,32,33,33,34,35,35,36,36,37,37,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,197,196,196,196,196,197,196,134,135,136,136,138,138,32,33,35,36,37,38,40,41,42,43,45,46,47,136,40,139,140,141,142,143,128,129,130,131,132,133,135,135,137,138,139,140,142,143,143,143,128,129,129,128,64,64,65,65,66,66,67,67,67,68,68,69,69,69,70,70,71,71,72,72,72,73,73,74,74,74,75,75,76,76,77,77,77,78,78,79,79,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,196,197,196,196,197,197,197,197,198,197,197,197,197,198,197,198,198,196,192,196,196,197,196,196,196,197,197,197,197,198,198,198,198,198,198,198,198,197,197,197,197,198,198,198,198,196,196,196,196,197,197,196,196,197,196,197,197,198,198,198,198,198,196,196,196,197,197,197,197,198,198,198,197,197,197,197,197,198,197,198,197,198,198,198,198,198,197,197,197,198,198,198,197,198,198,196,196,196,196,196,196,197,197,197,197,196,196,196,196,197,197,198,198,198,197,197,196,197,197,197,196,198,198,197,197,197,197,197,196,196,197,197,197,198,198,198,197,198,196,196,196,197,197,197,197,198,198,198,198,196,196,197,197,198,197,198,198 +,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,109,108,252,108,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,108,108,108,252,108,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,109,107,252,107,252,107,252,107,252,109,252,107,252,252,107,107,109,107,109,107,109,107,109,107,107,107,107,107,32,32,32,32,32,33,32,33,32,33,32,33,32,33,32,33,32,32,32,32,32,33,32,33,32,36,32,38,32,41,32,44,32,47,32,38,32,39,35,39,35,40,35,41,35,41,35,42,35,43,35,43,35,44,35,45,35,46,35,32,35,33,35,33,35,34,35,35,35,36,35,37,35,38,35,38,35,39,35,40,35,41,35,42,35,43,35,44,35,45,36,45,36,46,36,41,36,42,36,42,36,42,36,42,36,42,36,42,36,43,36,43,37,43,37,43,37,32,37,33,37,35,40,36,40,38,40,39,40,40,40,41,40,43,42,44,42,45,42,47,44,32,43,33,44,34,43,35,44,36,43,33,44,37,43,41,44,45,43,41,44,42,43,43,44,44,43,45,44,46,42,47,32,46,34,46,35,32,37,34,38,37,40,40,41,43,43,45,44,32,46,46,47,38,39,38,39,38,39,38,39,38,39,32,33,33,35,35,36,36,38,38,39,39,41,41,42,42,44,44,44,32,33,33,34,34,35,35,37,36,38,38,39,39,40,40,41,41,43,42,44,44,45,45,46,46,47,59,60,61,63,63,48,49,50,50,52,52,54,54,55,56,57,57,59,59,61,61,62,63,64,64,64,65,65,66,66,66,67,67,67,68,68,68,69,69,70,70,70,70,71,71,72,72,70,69,70,70,71,70,72,71,72,72,73,72,74,73,74,74,75,74,75,75,76,75,76,76,77,76,77,77,78,78,79,78,79,219,219,219,196,196,196,196,196,196,196,196,196,197,197,198,198,197,198,198,198,198,196,198,197,196,197,196,196,196,197,196,197,197,198,198,198,197,198,198,198,197,198,198,197,197,198,197,198,197,198,196,196,196,197,197,198,196,196,196,197,196,197,197,198,197,198,196,197,196,197,197,197,197,198,197,198,198,197,197,197,197,197,197,198,197,198,198,198,198,198,198,197,196,197,197,198,198,198,197,196,196,196,196,197,196,197,197,198,197,198,196,197,196,197,197,198,197,198,198,198,197,198,197,198,197,196,197,198,197,198,196,197,198,196,196,197,197,198,197,198,198,198,198,196,196,197,196,197,197,198,197,198,198,196,196,197,197,198,197,198,198,198 +,252,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,108,108,108,108,109,252,109,108,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,108,108,108,108,108,108,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,109,107,252,107,252,252,252,252,252,252,252,107,107,107,109,109,109,109,109,107,109,107,109,107,107,107,35,33,35,34,35,39,35,44,35,33,35,34,35,34,35,34,35,34,35,32,35,33,35,34,35,34,35,35,35,36,35,37,35,37,35,38,35,39,37,40,37,41,37,41,37,32,37,35,37,37,37,40,37,43,37,45,37,47,38,32,38,33,38,34,38,34,38,35,38,36,38,37,38,37,38,38,38,39,38,40,38,41,38,41,38,42,38,43,39,44,40,44,39,45,40,46,39,47,40,42,39,42,40,43,39,43,40,43,39,43,42,43,42,44,42,44,42,44,42,44,43,44,43,33,43,35,43,37,43,39,43,42,47,44,47,46,47,46,47,46,47,32,47,33,47,34,47,35,47,35,47,36,47,37,47,38,47,38,47,39,47,40,47,41,47,41,47,42,47,43,47,44,47,45,47,45,47,46,47,47,47,45,47,40,40,40,41,40,32,32,33,33,34,34,34,35,35,35,36,36,37,37,37,38,38,38,39,35,36,39,40,40,41,41,42,42,43,43,43,44,43,44,44,44,45,44,45,46,44,45,46,46,46,46,46,47,102,47,103,96,103,98,96,98,98,97,97,54,98,55,99,56,57,58,58,58,102,100,54,55,55,56,56,57,57,58,58,58,62,62,62,62,63,63,65,64,63,66,63,65,65,64,65,66,65,66,67,67,68,66,68,69,70,70,71,71,72,72,70,70,70,70,71,71,72,72,72,72,73,73,74,74,74,74,75,75,76,76,76,77,77,77,78,78,78,79,79,196,196,196,196,196,197,197,197,197,197,197,198,198,198,198,198,197,198,196,196,196,196,196,196,196,197,196,197,196,197,197,198,197,198,197,198,198,198,198,219,219,219,219,219,219,219,219,219,196,196,196,197,197,197,196,196,196,196,197,197,197,197,197,198,198,196,196,197,197,197,197,197,197,198,198,197,197,197,197,197,197,198,197,198,198,198,198,198,198,198,197,197,197,198,198,198,198,196,196,196,196,197,197,197,197,198,198,198,196,196,196,197,197,197,197,198,198,198,197,197,197,197,197,196,197,197,198,197,196,197,197,197,198,198,197,197,197,198,198,198,198,198,196,196,196,197,197,197,197,198,198,196,196,197,197,198,197,198,198,198,198 +,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,109,108,252,108,252,252,252,108,252,108,252,252,252,252,252,252,252,252,108,252,252,108,252,252,108,108,252,108,109,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,252,107,252,107,252,107,252,107,252,107,252,107,252,252,252,107,109,107,109,107,109,109,109,107,109,107,107,107,107,34,37,35,37,37,37,38,37,40,37,41,37,43,37,44,37,46,37,34,37,34,38,35,38,35,38,32,38,33,38,35,38,36,38,37,38,38,40,39,40,40,40,41,40,32,40,33,40,34,40,35,40,36,40,36,40,37,40,38,41,39,41,40,41,41,41,42,41,43,41,44,41,44,41,45,41,46,41,38,41,39,41,40,41,40,41,41,41,42,44,43,43,43,44,44,43,45,44,45,43,46,44,47,43,43,44,44,43,44,44,44,47,44,47,44,47,45,47,45,47,45,47,45,47,45,47,46,47,46,47,46,47,39,39,39,39,39,39,39,47,42,47,32,47,33,47,34,47,34,47,35,47,36,47,37,47,37,47,38,47,39,33,32,33,32,33,33,34,33,34,34,35,34,35,35,36,35,36,35,36,36,37,36,37,37,38,37,38,37,38,38,39,38,39,39,40,39,40,40,41,40,41,40,41,41,42,38,39,41,42,36,42,43,40,42,41,43,43,44,43,44,45,44,45,44,46,46,45,45,45,46,45,47,46,45,47,45,96,46,46,46,47,98,99,101,99,100,101,50,52,50,53,53,53,54,55,55,57,102,100,54,55,55,56,56,57,57,58,58,58,58,58,61,62,61,61,62,62,62,62,62,64,62,63,65,66,65,65,66,67,67,67,68,67,68,70,70,70,70,71,71,72,72,69,69,70,70,71,71,72,72,73,73,74,74,75,75,76,76,77,77,78,78,79,79,79,196,196,196,197,196,197,196,197,197,198,197,198,197,198,198,198,197,198,198,196,196,197,196,197,196,197,197,197,197,197,197,197,197,197,197,198,197,198,198,198,198,197,219,219,219,219,219,219,196,196,196,196,196,197,197,196,196,196,196,197,197,198,197,198,198,198,196,197,196,197,196,197,197,198,197,198,196,197,197,197,197,198,197,198,197,198,198,198,197,198,198,197,197,198,198,198,196,197,196,196,197,198,197,196,196,197,197,198,198,196,196,197,196,197,197,198,197,198,198,198,197,198,197,196,196,198,198,198,196,197,196,197,197,198,198,197,197,198,197,198,198,198,197,198,196,197,196,197,197,198,197,198,196,197,196,198,197,198,198,198,198,198 +,252,252,109,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,108,108,108,108,109,252,109,108,252,252,252,252,252,252,252,252,252,252,252,252,108,108,252,252,252,252,108,108,108,108,108,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,107,107,107,252,107,252,107,252,252,252,252,252,252,107,107,109,109,109,109,109,107,109,107,109,107,107,107,40,34,40,35,40,36,40,36,40,37,40,38,40,39,40,39,40,40,40,41,41,42,41,42,41,43,41,44,41,45,41,46,41,47,41,37,41,32,42,33,42,33,42,34,42,35,42,35,42,32,42,33,42,34,42,34,42,35,44,36,44,37,44,38,44,39,44,39,44,40,44,41,44,42,44,42,44,43,44,44,44,45,44,45,44,46,44,47,47,43,47,43,47,44,47,44,47,45,47,46,47,47,47,46,47,46,47,46,47,47,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,33,33,33,33,34,33,34,34,34,34,34,34,35,35,35,35,36,35,36,36,36,36,36,36,37,37,37,37,37,37,38,38,38,38,38,38,39,39,39,39,39,39,40,40,40,40,40,40,41,41,41,41,41,41,42,42,42,42,42,41,42,39,42,43,40,43,40,43,43,43,42,44,44,44,44,44,45,44,45,45,45,45,45,45,45,45,46,45,46,46,46,47,99,99,100,101,100,101,101,101,47,100,101,101,101,101,101,101,101,102,100,54,55,102,100,54,55,55,56,55,56,57,57,58,58,58,58,58,61,61,61,61,61,62,62,62,63,63,63,63,63,63,64,63,65,63,65,66,68,68,69,69,70,64,70,70,71,71,72,72,64,65,66,67,68,69,70,70,72,72,73,74,75,76,77,78,79,196,196,196,197,197,197,197,197,197,197,197,198,198,198,198,198,198,198,198,198,198,198,198,196,196,196,197,197,197,197,197,198,197,198,198,198,198,198,198,198,198,198,198,198,196,196,196,196,219,219,219,219,198,198,198,196,196,196,196,197,197,197,197,198,198,198,198,196,196,196,196,197,197,197,197,198,198,197,197,197,197,197,197,198,198,198,198,198,198,198,196,197,197,198,198,198,198,196,196,196,196,198,197,196,196,197,197,198,198,198,196,196,196,197,197,197,197,198,198,198,197,197,197,196,197,198,197,198,197,196,196,197,197,197,197,198,197,197,197,198,198,198,197,198,198,196,196,197,197,197,198,198,196,196,196,197,197,198,197,198,197,198,198 +,252,252,252,109,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,252,108,252,252,109,108,252,108,252,252,252,108,252,252,252,252,252,252,252,108,252,252,252,252,108,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,107,107,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,109,252,107,107,107,252,107,252,107,252,107,252,107,252,107,252,252,252,107,107,107,109,107,109,109,109,107,109,107,109,107,109,33,42,34,42,34,42,35,42,36,42,36,42,37,42,38,42,38,42,39,42,40,44,40,44,41,44,42,44,42,44,43,44,44,44,44,44,45,45,32,45,33,45,33,45,34,45,35,45,35,45,36,45,37,45,37,45,38,45,39,47,39,47,32,47,34,47,35,47,37,47,39,47,41,47,43,47,45,47,47,47,46,47,47,47,41,47,42,47,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,34,33,34,33,34,33,34,33,34,33,34,34,34,34,34,34,34,33,34,34,34,34,33,34,33,34,33,34,33,34,34,35,34,35,35,35,35,35,35,36,35,36,36,36,36,37,36,37,36,37,37,37,37,38,37,38,37,38,38,39,38,39,38,39,38,39,39,40,39,40,39,40,39,40,40,41,40,41,40,41,40,41,41,42,41,42,41,42,41,42,42,43,42,42,43,42,42,42,43,42,43,43,42,44,43,43,43,44,43,44,44,43,44,45,44,45,44,45,45,45,46,45,45,46,45,46,46,46,46,46,47,100,101,101,47,101,100,47,100,100,101,47,101,100,47,100,100,100,101,100,102,101,47,102,102,101,101,99,99,54,102,99,56,56,102,56,102,57,57,61,58,58,58,61,61,61,61,61,61,61,63,63,63,63,63,63,64,61,64,61,65,67,68,67,68,69,69,70,70,70,70,71,71,72,72,75,73,72,76,64,78,76,77,196,196,196,196,197,196,197,196,197,197,198,197,198,197,198,197,198,198,198,197,198,196,197,196,197,196,197,196,197,197,197,197,198,197,197,197,197,198,198,198,198,198,198,197,198,198,198,197,197,197,196,219,219,219,219,219,219,219,219,219,198,196,197,197,198,198,198,197,198,196,197,196,197,197,198,197,198,196,197,196,197,197,198,197,198,197,198,197,198,198,198,196,197,197,198,198,198,198,196,196,196,196,196,197,196,196,197,197,198,197,198,196,196,196,197,196,197,197,198,197,198,197,198,197,196,197,198,197,198,196,197,196,197,197,198,197,198,198,198,197,198,197,198,198,198,198,198,196,197,197,198,197,198,197,196,196,197,196,198,197,197,197,198,198,198 +,252,252,252,252,108,252,108,252,108,252,108,108,108,252,252,252,252,252,252,252,252,252,108,252,252,252,252,108,109,108,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,252,252,252,252,107,107,109,252,107,252,107,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,107,107,252,107,252,252,252,252,252,252,252,252,107,107,107,107,109,109,109,109,109,107,109,107,107,107,44,33,45,34,44,35,45,35,44,36,45,37,44,37,45,38,44,39,45,39,47,40,47,41,47,41,47,42,47,43,47,44,47,44,47,45,47,46,47,46,47,32,47,33,47,34,47,35,47,35,47,36,47,37,47,38,47,39,32,32,32,32,32,32,32,32,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,37,42,47,35,36,35,36,35,36,35,36,36,36,36,37,36,37,37,37,37,37,37,37,37,38,37,38,38,38,38,38,38,38,38,39,39,39,39,39,39,39,39,40,39,40,40,40,40,40,40,40,40,41,40,41,41,41,41,41,41,41,41,42,42,42,42,42,42,42,42,43,42,43,43,43,43,43,43,43,43,43,42,43,42,43,43,43,44,44,44,43,44,44,44,45,44,45,45,45,45,45,45,45,46,46,45,46,46,46,46,46,47,47,47,47,46,100,100,100,46,100,47,47,101,47,101,101,47,101,100,47,100,100,100,101,100,102,101,47,102,102,101,101,99,99,54,102,99,56,56,102,56,56,57,58,57,58,58,60,60,60,61,61,61,61,61,61,61,61,62,63,63,63,63,61,65,61,68,61,69,69,70,70,70,70,71,71,72,72,69,74,68,70,196,196,196,196,196,197,197,197,197,197,197,198,197,198,198,198,198,198,198,198,198,196,196,196,196,197,196,197,197,197,197,197,197,197,197,198,197,198,198,197,197,197,197,196,198,198,198,198,197,198,197,197,197,196,196,196,196,196,196,219,219,219,219,219,219,219,219,219,219,219,219,219,219,197,197,198,198,198,198,196,196,197,196,197,197,197,197,198,198,198,198,198,198,198,196,197,198,198,198,198,196,196,196,196,197,198,196,196,197,197,197,198,198,198,196,196,196,197,197,197,197,198,198,198,197,196,197,198,197,196,196,197,196,197,197,197,197,198,198,198,197,198,197,198,198,198,197,198,198,196,197,197,197,198,198,198,196,196,196,197,197,197,197,198,198,198,198 +,252,252,252,108,252,109,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,252,252,252,107,109,107,109,107,107,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,109,109,107,107,107,107,252,107,252,107,252,107,252,107,252,107,252,252,109,107,109,107,109,107,109,107,109,107,109,107,109,107,47,38,47,32,47,33,47,34,47,35,47,36,47,37,47,38,47,39,47,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,41,43,41,42,41,42,42,44,45,47,32,32,32,32,32,32,32,32,34,33,34,33,34,32,33,36,37,39,40,42,43,46,47,33,34,33,34,33,34,33,34,33,34,33,34,33,34,34,35,35,35,32,37,42,47,35,35,35,35,35,35,35,36,35,36,35,36,35,32,35,37,40,42,45,47,36,37,36,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,38,37,38,38,38,38,39,38,39,38,39,38,39,38,39,39,40,39,40,39,40,39,40,39,40,40,40,40,41,40,41,40,41,40,41,41,41,41,41,41,42,41,42,41,42,41,42,42,42,42,43,42,43,42,43,42,43,42,43,43,44,43,44,44,43,43,44,43,43,44,43,43,43,43,42,43,44,44,44,44,44,45,45,44,45,44,45,45,45,46,45,46,45,46,45,46,46,46,46,47,46,47,46,47,46,100,47,99,99,99,47,100,100,100,100,100,100,101,47,101,100,47,100,100,100,101,100,102,101,47,102,102,101,101,99,99,54,102,99,56,56,102,102,56,56,56,58,58,57,58,57,62,57,57,101,58,61,61,62,61,61,62,62,62,62,63,62,63,63,64,64,64,94,93,64,95,66,92,65,72,196,196,196,196,197,196,197,197,197,197,198,197,198,197,198,197,198,198,198,197,198,130,196,196,197,196,196,196,197,196,197,197,198,197,198,197,198,197,198,198,198,196,197,198,197,197,197,197,197,197,197,197,198,197,198,197,198,197,198,197,198,196,196,196,196,196,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,198,198,198,196,196,197,197,198,198,198,198,198,196,196,196,196,196,196,196,196,196,197,197,198,198,198,197,196,196,197,196,197,197,198,197,198,196,197,197,198,197,196,196,197,196,197,197,198,197,198,197,198,198,198,197,198,197,198,198,198,197,198,196,197,197,198,198,196,196,197,196,197,197,197,197,198,198,198,198,198 +,252,252,252,252,108,252,109,252,252,252,108,252,108,252,108,252,252,252,252,252,108,252,108,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,252,252,107,107,107,107,109,252,107,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,107,107,107,107,252,107,252,107,252,252,252,252,252,252,252,107,107,107,109,109,109,109,109,107,109,107,109,107,109,32,32,32,32,32,47,44,42,39,37,34,32,32,33,33,35,35,36,37,38,38,39,40,41,41,42,43,44,45,45,46,47,33,33,33,33,34,33,33,34,35,37,38,40,41,42,44,46,47,33,33,33,34,33,34,33,34,34,35,34,35,34,35,34,35,34,35,34,35,35,35,35,35,35,35,35,35,35,35,35,35,32,39,47,35,35,35,36,37,36,37,36,37,36,37,36,47,32,35,38,41,44,47,37,37,37,37,37,37,38,38,38,38,38,38,38,38,38,39,38,47,45,42,40,37,34,32,38,39,38,39,39,39,39,38,39,38,39,38,39,39,39,39,39,39,39,39,39,39,39,39,40,40,40,40,40,40,40,40,41,40,41,40,41,41,41,41,41,41,41,41,42,41,42,41,42,42,42,42,42,42,42,42,43,43,43,43,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,44,43,44,44,44,45,43,43,44,44,44,45,44,45,45,45,45,46,45,46,45,45,46,46,46,46,46,46,46,46,47,46,47,46,47,47,47,46,99,47,47,47,47,99,99,99,100,100,100,101,101,101,101,47,101,100,47,100,100,100,101,100,102,101,47,102,102,101,101,99,99,54,102,99,56,56,102,55,55,56,56,57,57,58,58,58,60,61,58,61,61,61,62,62,62,63,63,62,63,61,62,62,63,62,90,62,94,91,90,94,91,94,92,93,93,196,196,196,196,197,197,197,197,197,197,198,198,198,198,198,198,198,198,198,198,128,129,196,196,196,196,197,197,197,197,197,197,197,197,198,198,198,198,198,196,196,197,197,197,197,197,197,196,196,197,197,198,198,197,198,197,198,197,198,198,198,198,198,198,198,198,198,197,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,196,196,196,196,197,197,198,198,198,196,197,197,198,198,198,198,198,196,196,197,197,197,198,198,198,196,197,197,198,198,196,196,196,196,197,197,197,197,198,198,198,198,198,197,198,197,198,198,198,197,198,198,198,196,198,198,198,196,196,196,197,196,197,197,198,197,198,198,198,198 +,252,252,252,108,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,252,252,109,107,109,107,109,252,252,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,252,107,252,107,109,107,252,107,252,107,252,109,252,109,109,107,109,107,109,109,109,109,109,107,109,107,109,107,33,34,33,34,33,46,45,42,47,42,47,47,33,34,33,34,33,34,33,35,34,35,34,32,35,36,39,40,43,44,47,35,34,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,36,36,37,36,36,36,37,36,36,36,37,36,32,34,35,38,39,42,43,46,46,36,37,36,37,36,37,36,37,37,38,38,38,47,32,35,36,39,40,43,44,47,38,38,39,38,39,39,39,38,39,39,40,39,40,39,40,39,40,39,38,32,35,40,43,47,39,38,39,38,39,38,39,38,39,39,39,39,38,39,38,39,47,43,46,47,47,40,39,40,47,40,32,40,40,41,40,37,42,47,40,41,41,41,35,40,43,47,41,42,41,42,41,42,42,32,34,38,41,44,47,43,42,43,42,43,43,44,43,44,43,44,43,44,44,46,46,46,44,45,45,45,45,46,47,47,44,46,47,44,46,44,45,45,45,45,46,45,46,45,46,45,46,47,47,46,47,47,103,47,96,47,96,97,47,96,97,97,98,97,97,98,98,98,98,99,99,99,99,99,99,99,99,100,100,101,47,101,100,47,100,100,100,101,100,102,101,47,102,102,101,101,99,99,54,102,99,56,56,102,55,55,56,56,57,55,58,57,58,61,58,60,61,62,61,61,62,62,63,63,62,62,62,62,62,63,62,91,91,92,90,92,92,91,92,93,93,94,128,130,130,131,132,134,134,136,136,138,138,140,141,142,143,128,143,142,135,138,140,143,136,196,196,196,196,197,196,197,197,197,197,198,197,198,197,198,196,197,197,197,197,197,197,196,196,197,196,197,196,198,196,197,197,198,197,198,197,198,197,198,197,198,198,198,197,198,198,198,197,220,220,220,220,220,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,196,196,196,197,196,197,197,198,197,198,196,197,198,198,197,198,197,196,196,198,198,198,196,197,196,197,197,198,197,198,196,197,196,197,196,197,197,198,197,198,197,198,197,198,197,198,198,198,198,198,197,198,197,198,197,198,196,198,196,197,196,197,197,198,197,198,198,198,198,198 +,252,252,252,252,108,252,108,252,109,252,108,252,252,252,252,252,108,252,109,252,109,252,108,252,108,108,252,108,108,252,252,252,252,252,252,252,252,252,109,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,252,252,252,252,107,107,109,252,109,252,107,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,107,109,107,109,107,109,109,252,109,252,109,107,107,109,109,109,109,109,107,109,107,109,107,109,107,34,34,34,34,34,35,34,35,34,35,34,34,34,35,34,35,32,34,35,37,39,40,42,44,46,47,35,36,35,36,35,36,35,36,36,36,36,36,36,36,36,36,36,34,36,37,38,39,41,42,43,44,46,47,36,37,33,34,36,36,38,39,40,41,43,43,45,46,47,38,38,38,38,38,37,38,38,38,38,38,38,38,37,38,38,39,39,40,39,40,39,39,39,40,39,40,39,40,39,39,40,40,40,40,40,40,32,34,36,38,41,43,45,47,40,41,39,41,40,41,40,41,40,41,40,41,40,32,34,36,38,40,43,45,47,40,41,40,40,40,40,40,40,40,41,40,41,41,41,41,41,41,41,41,41,41,42,42,42,42,42,42,42,42,43,42,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,96,96,99,99,99,46,46,99,47,100,46,100,99,99,100,100,47,100,46,100,100,101,101,101,102,45,102,46,102,102,102,102,102,103,103,103,103,96,96,96,97,97,97,97,98,98,97,97,98,98,98,53,99,101,47,101,100,47,100,100,100,101,100,102,101,47,102,102,101,101,99,99,54,102,99,56,56,102,102,100,54,55,55,56,56,57,57,58,58,58,60,60,60,61,61,61,61,61,62,62,62,196,196,196,196,196,63,60,61,61,62,62,92,62,92,92,93,92,94,94,94,94,128,129,130,130,131,132,133,134,135,135,136,137,138,139,140,141,142,70,71,71,72,72,73,136,196,136,197,196,197,197,197,197,197,197,198,197,198,198,197,197,197,196,197,197,197,197,196,196,196,196,196,196,197,197,197,197,198,198,198,198,198,197,198,197,198,198,198,198,198,198,198,198,198,198,198,222,221,221,221,221,221,221,220,220,220,220,220,220,220,220,220,220,220,220,220,219,219,219,219,219,219,219,219,196,196,196,197,197,197,197,197,197,198,198,198,197,198,197,198,197,198,198,198,197,198,197,198,196,197,197,197,197,198,196,196,196,197,197,197,197,197,197,198,198,198,197,197,197,198,198,198,198,198,197,198,198,198,197,198,197,196,198,196,196,197,197,197,197,198,197,198,198,198,198 +,252,252,252,109,252,108,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,252,252,107,107,109,107,252,107,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,109,107,252,107,252,107,109,107,252,107,252,252,109,107,109,107,109,107,109,109,109,107,109,107,109,107,107,36,35,36,35,36,36,36,36,36,36,36,35,36,36,36,36,36,36,37,37,37,37,37,37,37,37,34,36,37,39,39,41,42,44,44,46,47,37,38,37,38,37,38,37,38,37,38,37,38,37,38,38,38,38,38,38,39,39,39,39,39,39,39,39,39,39,39,39,40,39,40,39,40,39,40,39,40,39,40,39,32,34,34,36,36,38,39,40,41,43,43,45,45,47,41,41,41,41,41,41,42,42,42,42,42,42,42,42,43,42,43,42,43,42,43,42,41,42,42,42,34,37,38,41,42,45,47,42,42,42,42,42,42,42,42,42,42,42,40,41,41,42,41,42,41,42,41,42,42,43,32,36,39,44,47,43,43,44,43,45,46,46,43,44,44,45,44,45,44,45,44,45,45,45,45,45,46,45,45,46,46,45,44,46,44,46,47,44,46,47,103,103,97,97,98,98,99,99,97,98,99,100,100,97,98,49,100,101,101,101,102,100,101,102,101,103,101,103,102,103,102,103,51,52,96,96,97,97,52,53,97,98,53,98,98,97,97,98,54,98,98,99,98,56,98,56,55,56,55,56,56,57,56,57,57,99,57,58,57,58,57,58,58,59,58,59,58,59,59,59,59,60,59,60,60,61,60,61,60,61,61,61,60,61,61,63,63,63,196,196,196,196,196,196,197,198,198,198,61,62,62,63,63,63,93,92,93,93,94,94,93,94,94,94,95,95,94,95,64,65,65,66,66,67,67,68,68,69,69,70,70,71,71,72,136,136,136,197,196,136,196,198,197,198,197,198,197,198,197,198,196,196,196,197,196,197,197,197,197,196,197,198,196,197,196,197,197,198,197,198,197,198,197,198,198,198,197,198,197,198,197,198,197,198,198,198,198,198,198,198,222,222,222,222,222,222,221,222,221,221,221,221,220,221,220,221,220,220,220,220,220,220,220,220,219,196,196,197,196,197,197,198,197,198,197,198,198,198,197,198,197,198,197,198,197,198,197,198,197,196,196,197,197,198,198,197,196,197,196,197,197,198,197,198,197,198,198,198,197,198,197,198,197,198,198,198,197,198,198,198,197,196,197,198,196,197,196,197,197,198,197,198,198,198,198,198 +,252,252,108,252,108,252,108,252,252,252,108,252,108,252,109,252,252,252,109,252,109,252,108,252,252,252,108,108,108,252,108,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,107,107,107,107,109,252,107,107,107,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,109,107,107,107,252,109,109,109,252,252,252,252,107,107,107,107,109,109,109,107,109,107,109,107,109,107,107,37,37,33,35,36,37,38,40,41,42,43,45,46,47,39,41,43,45,47,38,38,38,38,38,38,38,38,38,38,38,38,38,39,39,39,38,34,36,37,38,39,40,41,42,43,45,46,47,39,39,40,39,40,39,40,40,40,40,40,40,40,40,40,40,40,40,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,42,42,42,43,42,43,42,43,42,43,42,43,42,43,47,44,41,38,35,32,40,47,43,44,44,44,44,44,44,44,44,44,42,44,44,44,43,44,44,44,47,45,43,41,40,37,36,34,32,43,44,43,44,43,42,42,32,33,35,36,37,38,40,41,42,43,45,46,47,44,45,45,45,45,97,98,98,98,98,98,46,32,35,38,41,44,47,47,47,99,99,100,100,100,100,100,100,45,101,46,101,101,46,101,46,102,102,102,96,97,97,96,98,99,50,50,99,99,98,50,51,99,100,51,52,51,101,102,102,102,102,52,53,53,53,53,53,53,53,53,54,54,54,54,54,54,55,55,55,55,55,55,56,56,98,56,56,56,56,98,57,57,57,57,57,57,58,57,58,58,58,58,59,100,59,59,59,59,59,59,60,60,60,60,60,60,61,60,61,61,61,61,61,61,62,62,62,62,62,63,63,63,196,196,196,197,197,198,197,197,198,198,198,198,198,198,92,62,63,92,93,92,93,93,94,94,94,94,64,94,65,64,66,65,67,66,67,67,68,68,68,68,69,69,69,70,71,71,71,135,136,136,136,136,136,198,197,198,198,198,198,198,198,196,196,196,196,196,196,196,197,197,197,197,197,197,198,198,198,197,197,197,198,197,198,198,198,198,198,197,198,197,198,197,198,198,198,197,198,198,198,198,198,198,198,198,198,198,198,222,222,222,222,222,222,222,222,221,221,221,221,221,221,221,221,220,221,220,220,220,196,196,196,196,197,197,197,197,198,198,198,198,198,198,198,197,198,198,198,197,198,198,198,197,198,198,196,196,197,197,198,196,197,197,197,197,197,197,197,197,198,198,198,197,198,197,198,197,198,198,198,197,198,198,198,197,198,196,197,198,196,196,197,197,197,197,198,198,198,198,198,198 +,252,252,252,109,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,107,109,252,252,107,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,107,107,109,107,109,107,252,107,252,107,252,107,252,109,252,109,252,107,109,107,109,107,109,109,109,107,109,107,109,107,107,107,38,39,38,39,34,34,37,37,39,40,42,42,45,45,47,39,39,40,39,40,39,40,39,40,39,40,39,40,39,40,39,40,40,41,40,40,40,41,40,41,40,41,40,40,40,41,40,41,40,41,41,41,41,41,41,42,41,42,42,42,41,42,41,42,41,42,42,43,42,43,42,43,42,43,42,43,42,43,42,43,42,43,42,44,43,44,44,44,44,44,44,44,44,44,44,44,44,44,44,46,45,46,45,46,45,46,45,46,45,46,45,47,45,42,40,37,35,32,47,45,45,45,45,46,45,45,45,45,45,45,45,45,46,45,46,46,46,44,45,44,45,45,42,43,43,43,43,43,43,46,47,46,47,47,47,96,97,97,97,98,99,99,99,99,99,99,100,100,99,100,100,100,100,100,101,100,101,101,100,101,100,100,100,101,102,101,102,102,102,102,103,103,51,103,97,97,96,51,52,98,52,99,53,52,53,52,53,53,101,101,54,53,54,53,54,54,55,54,55,54,55,54,55,55,56,55,56,55,56,55,56,56,57,56,57,56,57,57,57,57,58,57,58,57,58,58,58,58,59,58,59,58,59,59,60,59,60,59,60,60,60,60,61,60,61,60,61,61,61,61,61,62,61,62,62,62,63,63,62,62,63,63,63,63,143,143,196,197,198,198,198,198,198,197,198,198,198,198,198,198,198,92,93,93,92,94,94,64,66,65,66,64,66,65,66,67,67,67,68,68,67,67,68,68,68,68,69,69,70,70,70,71,71,71,135,137,138,140,140,141,142,142,143,128,129,196,140,140,140,141,141,142,142,143,198,197,198,198,198,197,198,198,198,197,198,197,198,197,198,198,198,198,197,197,198,197,198,197,198,197,198,198,198,197,198,197,198,197,198,198,198,197,198,198,65,65,66,217,222,222,222,222,222,221,221,221,221,220,221,220,221,220,196,196,197,196,197,196,197,196,197,197,198,197,198,198,198,197,198,197,198,197,198,197,198,197,198,197,198,196,197,197,198,196,197,196,197,196,197,197,198,197,198,197,198,198,198,197,198,197,198,198,198,198,198,197,198,198,198,197,196,197,198,196,197,196,197,197,198,197,198,198,198,198,198 +,108,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,109,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,252,252,109,107,107,107,107,107,107,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,107,109,107,252,109,252,109,252,252,252,252,107,107,109,107,109,109,109,109,109,107,109,107,109,107,107,107,39,40,47,39,32,34,37,39,42,44,47,40,39,40,40,40,96,34,36,38,41,43,45,47,40,41,40,41,40,41,40,42,41,42,41,42,41,42,41,42,41,42,41,42,41,42,41,42,42,43,42,43,42,42,43,43,42,43,32,33,34,34,36,36,37,38,39,40,41,42,43,43,44,45,46,47,43,44,44,44,44,47,46,44,43,41,40,38,37,35,34,32,45,45,45,46,45,46,47,47,46,33,35,36,37,38,40,47,42,43,45,46,47,47,96,96,34,36,38,39,41,43,45,47,97,97,97,33,35,36,37,38,40,41,42,43,45,46,47,99,100,45,45,45,45,45,44,45,45,46,102,103,96,96,97,96,97,41,43,41,44,47,99,99,100,100,100,100,100,100,100,101,50,50,101,50,101,101,51,101,101,101,51,51,101,102,101,103,101,103,103,103,53,53,96,96,53,53,53,53,54,54,54,54,54,54,54,54,55,55,55,55,55,55,55,55,56,56,56,56,56,56,56,56,57,57,57,57,57,57,57,57,58,58,58,58,58,58,58,58,59,59,59,59,59,59,59,59,60,60,60,60,60,60,60,60,61,61,61,61,61,61,61,61,62,62,62,62,62,61,62,62,62,62,62,62,63,48,63,63,63,53,63,197,128,128,143,143,198,143,198,198,198,198,198,198,198,198,198,198,132,132,93,94,94,92,93,64,65,93,68,66,66,68,67,67,68,68,68,68,70,68,68,69,69,69,70,70,70,70,71,71,72,72,73,73,73,73,138,138,138,138,139,139,139,139,140,140,140,140,141,141,141,141,141,142,142,142,143,143,143,143,143,198,198,198,198,198,198,198,198,198,198,198,198,197,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,66,66,217,78,217,217,222,222,222,221,221,221,221,220,221,220,220,198,196,196,196,196,197,197,197,197,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,196,196,197,198,197,197,197,197,197,197,197,197,198,198,198,198,197,197,197,197,198,198,198,198,198,197,198,198,198,198,196,197,197,198,196,196,197,197,197,197,198,197,198,198,198,198 +,252,108,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,107,107,252,107,252,107,252,107,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,107,107,107,107,252,107,252,107,252,107,252,107,109,107,252,109,252,109,107,107,109,107,109,109,109,107,109,107,109,107,107,107,107,41,41,41,41,41,41,41,41,41,41,41,41,41,41,42,41,42,42,42,42,42,42,42,42,42,42,42,42,42,42,32,35,38,41,44,47,43,43,43,43,43,43,103,101,100,101,100,101,100,101,101,103,103,44,45,44,45,44,45,44,45,44,45,44,45,45,46,45,46,45,46,45,46,45,46,45,46,45,46,45,46,45,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,96,97,96,98,97,98,98,99,99,101,100,102,101,102,101,103,102,103,96,96,96,96,96,96,96,96,97,96,97,48,48,97,48,46,97,57,48,57,97,48,98,52,98,99,99,100,100,46,100,45,100,100,46,102,101,103,103,97,103,97,97,98,98,98,50,99,50,99,51,99,100,100,101,100,51,52,51,52,52,53,52,53,52,53,102,53,53,102,53,54,53,103,53,96,54,55,54,55,54,55,54,55,55,56,55,56,55,56,55,56,56,57,56,57,56,57,56,57,57,58,57,58,57,58,57,58,58,58,58,59,58,59,58,59,59,59,59,59,59,60,59,60,60,60,60,60,60,61,60,61,60,61,61,61,61,62,61,62,61,62,61,62,62,62,62,63,62,62,62,62,62,62,63,62,63,62,61,62,60,61,63,88,63,63,63,143,143,143,128,128,143,128,131,129,131,129,132,132,132,132,133,133,133,92,65,65,93,66,64,66,92,64,67,64,69,67,69,70,70,70,70,70,69,70,70,69,69,70,70,71,70,72,71,72,72,73,73,74,73,74,74,75,75,76,75,76,76,77,77,78,77,78,78,79,79,79,64,79,64,64,64,65,64,66,65,66,66,67,67,68,132,132,132,132,133,133,134,134,135,135,198,136,198,198,198,198,197,198,198,198,198,198,198,198,198,198,198,198,198,198,77,217,77,217,77,217,222,222,222,221,221,221,220,220,219,219,219,198,196,197,196,197,196,197,197,198,197,198,197,198,197,198,197,198,197,198,197,198,197,196,196,196,197,198,196,197,196,197,197,198,197,198,197,198,198,198,197,198,197,198,197,198,197,198,198,198,197,198,198,198,196,197,197,198,196,197,196,197,197,198,197,197,198,197,198,198 +,108,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,107,107,107,107,107,107,107,107,107,107,252,107,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,109,107,109,107,252,109,109,109,252,252,252,252,252,109,107,107,109,109,109,109,109,107,109,107,107,107,107,107,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,44,44,44,44,44,34,36,38,40,43,45,47,34,36,37,38,39,41,42,43,44,46,47,45,46,45,46,45,46,45,46,45,46,45,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,96,96,47,44,41,38,35,32,98,98,47,43,40,36,32,99,99,99,100,100,100,47,43,39,36,32,35,38,41,44,47,102,103,102,102,102,102,102,102,57,97,41,43,41,42,41,42,44,45,47,46,61,46,49,99,61,99,49,102,98,100,98,100,100,100,43,100,46,102,101,102,102,102,102,103,96,96,96,97,98,52,97,52,52,53,53,53,53,53,53,53,53,54,53,54,54,101,54,54,54,54,54,55,54,55,55,55,55,55,55,56,55,56,56,56,56,56,56,56,56,57,57,57,57,57,57,57,57,58,58,58,58,58,58,58,58,59,58,59,59,59,59,59,59,60,59,60,60,59,60,60,60,59,60,60,60,61,61,61,61,61,61,62,61,62,62,62,62,62,62,62,62,63,63,63,63,63,63,60,60,61,61,61,63,61,61,62,62,62,63,62,62,62,61,62,62,59,61,88,88,88,88,89,59,62,89,63,89,89,67,91,65,65,66,92,68,92,65,66,68,65,67,66,68,67,68,65,68,67,68,68,68,70,70,71,70,71,70,70,71,71,70,71,71,71,71,72,72,72,72,73,73,74,74,74,74,75,75,76,76,76,76,77,77,77,77,78,78,78,78,79,79,79,64,79,64,64,64,65,65,65,65,66,66,67,67,68,68,68,68,69,70,70,70,71,71,72,72,73,73,73,73,74,74,75,75,76,76,76,76,76,76,76,77,77,77,217,77,217,217,217,222,222,221,221,221,221,220,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,198,198,198,198,198,198,198,198,196,196,196,196,196,196,198,197,197,197,197,197,197,198,198,198,198,198,198,197,197,198,197,198,197,198,198,198,197,198,198,198,198,196,197,197,198,196,196,197,197,198,198,198,198,198,198,198,198 +,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,252,107,109,107,252,107,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,107,107,252,107,109,107,252,107,252,107,252,107,252,109,252,109,252,109,109,109,107,107,109,109,109,109,109,107,109,107,107,107,107,107,47,39,32,34,37,38,41,42,45,46,32,33,35,35,37,38,40,40,42,43,45,45,47,45,44,45,44,45,44,45,45,46,46,46,45,46,46,46,45,46,46,46,45,46,46,46,45,47,47,47,47,47,47,47,47,47,47,44,43,40,39,36,34,32,96,97,32,34,37,39,42,44,47,96,97,96,47,39,32,39,47,97,98,97,98,98,99,98,98,99,99,47,44,41,38,35,32,34,37,39,42,44,47,101,102,101,52,102,102,102,34,35,38,39,42,43,46,47,102,102,102,102,97,96,57,97,102,102,102,97,102,102,49,51,49,102,99,49,50,100,100,50,100,45,100,45,43,101,101,101,100,102,102,103,52,96,52,96,53,96,97,52,98,52,53,53,54,53,54,53,54,53,54,100,55,54,55,54,55,54,55,55,55,55,56,55,56,55,56,56,56,56,57,56,57,56,57,57,57,57,58,57,58,57,58,57,58,58,58,58,59,58,59,58,59,59,59,59,60,59,60,59,60,60,60,60,61,60,60,61,60,58,60,61,61,60,59,60,61,61,61,61,63,62,63,62,62,63,62,62,63,62,63,62,62,62,61,63,60,63,63,62,61,61,61,63,61,62,61,63,61,63,63,62,62,61,62,61,61,62,88,63,63,89,62,89,61,90,90,65,64,90,66,67,64,67,67,67,66,68,67,68,69,66,68,69,69,67,68,70,68,69,70,69,71,71,72,72,71,72,72,71,72,71,72,72,73,72,73,73,74,73,74,75,74,74,75,75,76,75,76,76,77,76,77,77,78,78,79,78,79,79,79,79,79,64,79,64,64,64,65,65,66,66,67,66,67,67,68,68,69,69,70,69,70,70,71,71,72,72,73,72,73,73,74,74,75,75,76,76,76,217,217,217,217,217,217,217,217,222,222,221,221,221,221,220,221,220,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,196,197,196,198,196,197,197,198,197,198,197,198,197,198,198,198,197,198,197,198,197,198,198,198,197,198,198,198,198,196,196,193,196,193,196,197,197,198,199,199,199,193,193,198,198,198 +,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,252,252,252,107,107,107,107,107,107,107,107,107,252,107,109,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,107,107,109,107,109,109,252,109,252,109,252,252,252,252,252,252,107,107,109,107,109,107,109,107,109,107,107,107,107,44,44,45,44,45,44,45,44,44,44,45,97,97,99,99,100,100,102,102,103,96,45,45,45,97,98,99,101,102,103,46,46,47,47,47,47,47,103,100,101,100,101,101,101,47,32,34,37,39,42,44,47,97,98,98,98,98,99,99,99,100,100,100,101,101,101,101,102,102,102,102,103,103,96,96,96,96,97,97,97,32,35,37,40,42,45,47,47,47,44,47,42,47,47,101,52,100,100,100,100,100,102,101,100,100,102,101,102,102,50,102,102,102,102,102,102,102,102,50,50,102,102,102,57,102,102,102,97,102,57,103,98,98,98,50,99,50,50,50,99,50,50,99,100,51,45,51,45,51,101,100,52,102,102,102,102,52,52,52,53,53,53,53,53,53,53,53,54,54,54,54,54,54,54,54,55,55,55,55,55,55,55,55,56,56,56,56,56,56,56,56,57,57,57,57,57,57,57,57,58,58,58,58,58,58,58,58,59,59,59,59,59,59,59,59,60,60,60,60,60,60,61,60,61,61,61,61,61,60,61,60,61,58,61,61,60,60,59,59,61,61,61,62,62,63,61,61,61,63,63,62,62,63,62,62,62,61,61,60,61,61,61,61,61,62,61,63,61,61,63,63,63,62,58,62,58,61,62,89,88,87,62,86,88,64,90,90,64,66,65,66,67,68,68,67,66,67,68,68,68,68,69,69,70,69,68,69,70,69,70,69,69,70,70,71,73,74,72,72,74,72,73,72,73,73,73,73,73,73,74,75,75,74,75,75,75,75,76,76,76,76,77,77,77,77,78,78,78,78,79,79,79,79,79,79,79,64,64,64,64,64,65,27,31,30,29,28,27,26,26,25,24,23,22,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,221,221,221,221,221,221,221,220,220,220,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,196,197,197,197,197,197,197,197,197,198,198,198,198,198,198,197,197,197,197,197,197,198,198,198,198,197,197,198,198,199,199,199,199,199,193,199,196,193,199,193,193,193,193,199,199,199,199 +,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,252,107,109,107,252,107,252,107,252,107,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,109,107,107,107,252,107,252,107,252,107,252,107,252,109,252,109,252,109,252,109,252,252,107,109,109,109,109,107,109,107,109,107,107,107,45,46,46,46,46,46,47,32,34,36,39,40,43,45,47,102,103,47,47,47,98,98,100,100,102,103,47,47,47,47,96,96,97,96,97,96,97,32,98,97,98,97,100,100,100,98,99,98,99,99,100,99,100,99,100,100,101,100,47,45,44,41,40,37,36,33,32,102,103,102,103,47,32,34,37,39,42,44,47,97,97,98,98,99,101,51,51,33,47,43,40,35,32,47,47,51,103,100,102,102,102,101,101,102,101,100,45,99,50,103,103,102,102,50,50,57,50,50,50,50,50,57,103,102,102,57,54,57,58,50,54,50,53,50,50,50,49,50,51,50,50,50,100,100,51,100,51,100,52,45,52,52,101,102,101,52,53,52,96,53,54,53,54,53,54,53,54,54,55,54,55,54,55,54,55,55,56,55,56,55,56,56,56,56,57,56,57,57,57,57,58,57,58,57,58,58,59,58,59,58,59,58,59,58,59,60,60,60,59,59,59,60,61,61,60,61,60,61,61,61,62,61,62,62,62,62,62,63,61,61,61,62,61,60,60,61,60,61,59,94,59,62,63,62,63,83,83,82,61,62,63,82,62,63,63,63,61,83,84,84,62,62,62,62,62,62,62,63,62,62,62,63,63,62,62,62,62,62,85,62,61,62,86,87,88,89,65,66,67,68,67,67,69,68,69,68,69,70,69,70,69,70,70,70,71,71,70,71,71,71,71,72,72,71,73,72,73,72,74,74,74,74,74,74,74,74,75,74,75,75,74,76,75,75,75,76,76,76,77,76,77,76,77,77,78,77,78,78,79,78,79,78,79,79,79,64,79,31,64,28,65,26,31,29,28,25,24,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,217,217,217,221,217,221,217,221,217,221,221,221,221,220,221,220,221,220,220,219,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,197,196,197,197,198,197,198,198,198,198,198,197,198,198,196,196,197,196,197,197,198,197,198,198,198,198,198,198,199,199,193,196,193,193,193,193,193,193,194,193,199,199,199,193,193,193,193 +,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,107,107,252,107,107,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,109,107,107,107,252,109,109,109,252,252,252,109,252,252,252,252,252,252,252,109,109,109,109,107,109,107,107,107,107,47,32,35,38,41,44,47,47,47,47,47,47,47,103,102,103,103,32,33,34,35,36,37,39,39,41,41,43,44,45,46,47,98,98,47,45,43,41,38,37,34,32,47,99,99,99,99,32,34,37,39,42,44,47,100,101,101,101,101,101,101,101,101,102,102,102,102,102,47,40,32,47,103,103,96,96,96,97,96,97,97,98,102,98,100,101,99,98,100,99,50,98,103,99,49,100,49,100,102,100,49,101,101,101,102,51,102,102,102,102,50,51,51,50,100,100,100,100,52,102,57,54,50,58,102,54,50,50,61,63,50,56,51,50,49,103,50,50,50,50,50,51,51,100,100,100,51,99,52,46,52,52,101,53,102,53,53,53,53,53,53,54,54,54,54,54,54,55,55,55,55,55,55,56,55,56,56,56,56,56,56,57,57,57,57,57,57,58,58,58,58,58,58,59,58,59,59,59,59,59,59,59,58,60,60,58,60,60,60,60,59,60,61,61,62,60,61,61,62,61,62,62,63,63,63,62,62,63,61,61,61,62,60,60,61,61,61,62,61,60,94,60,61,81,81,64,63,63,82,82,62,82,82,64,62,82,83,82,60,60,84,84,62,62,83,61,62,64,62,63,66,62,64,61,62,85,62,86,63,86,85,86,87,87,64,65,67,68,67,69,68,68,69,69,69,70,70,70,72,70,71,71,71,71,72,72,73,72,73,72,73,72,73,72,74,73,74,74,73,75,75,75,75,74,75,74,74,75,74,76,76,75,76,76,75,76,76,76,76,77,77,77,77,78,78,78,78,79,78,79,79,79,79,79,64,79,29,64,26,65,23,65,29,66,27,31,29,28,26,25,23,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,217,217,217,217,217,221,217,221,221,221,221,221,221,221,221,221,220,220,220,220,220,219,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,198,196,196,198,198,198,198,198,198,198,199,196,196,196,196,193,193,193,194,193,194,196,199,199,193,193,193,193,193,193,193 +,252,108,252,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,107,107,107,252,107,252,107,252,107,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,109,107,252,107,109,107,252,107,252,107,252,107,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,107,109,107,252,107,107,107,102,101,32,33,36,37,39,40,42,43,46,47,103,102,103,103,103,102,96,96,96,96,97,96,97,96,97,97,97,97,98,98,98,97,98,98,99,98,99,98,99,98,98,99,99,100,99,101,100,99,100,100,101,100,101,100,101,34,37,38,41,42,45,47,102,101,102,102,103,102,103,102,102,96,103,96,97,97,97,97,99,51,99,100,51,99,50,51,103,51,97,96,96,96,96,52,103,102,49,100,101,49,45,51,100,51,100,50,102,50,102,52,53,100,45,52,103,50,50,50,50,49,50,54,55,50,50,55,54,59,52,50,50,50,50,53,50,50,51,50,51,51,51,51,52,51,100,52,52,100,53,52,53,53,53,53,54,53,54,53,54,54,55,54,55,55,55,55,56,55,56,55,56,56,57,56,57,56,57,57,58,57,58,57,58,58,59,58,59,58,59,59,60,59,60,59,60,60,60,61,59,60,59,61,59,60,60,60,88,59,60,61,61,61,61,62,62,63,61,62,62,62,62,61,63,63,63,61,63,62,63,62,61,94,61,61,59,62,93,60,60,62,63,64,81,64,81,65,82,82,65,82,64,83,63,65,83,83,66,83,83,83,62,64,84,83,67,65,67,66,63,67,64,64,85,65,86,65,87,65,69,86,69,66,67,69,69,70,70,70,71,70,70,70,71,71,72,71,72,73,72,74,73,74,74,73,73,73,74,73,74,73,74,75,74,74,74,75,75,74,76,75,76,75,76,75,74,75,75,76,77,75,76,76,76,76,77,76,77,77,78,77,78,78,78,78,79,78,79,78,79,79,79,64,79,64,64,64,65,25,65,24,66,22,67,26,67,25,25,23,31,29,28,25,24,22,218,218,218,218,218,218,218,218,218,217,218,217,218,217,217,217,217,221,217,221,217,221,221,221,221,221,221,220,221,220,221,220,221,220,220,220,220,219,220,219,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,198,199,196,196,193,196,193,196,193,194,193,194,199,199,196,196,193,193,193,193,194,193,194 +,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,107,107,107,109,107,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,107,107,109,107,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,107,107,107,107,102,101,102,102,102,102,102,102,102,102,34,35,37,38,40,41,43,44,46,47,96,96,32,34,36,38,41,43,45,47,99,99,98,98,98,98,98,98,98,98,99,98,99,99,99,102,49,99,100,100,100,100,46,101,101,100,102,101,101,101,101,101,102,101,100,102,102,102,103,103,103,98,101,103,51,97,97,51,52,101,100,51,102,53,102,51,97,51,97,49,98,49,52,102,50,102,50,101,50,50,101,49,102,51,100,100,51,51,100,103,51,51,51,51,97,51,51,51,52,51,51,49,48,48,48,50,55,52,50,50,50,50,50,50,50,50,51,50,51,51,51,51,52,52,52,52,53,52,53,53,53,53,53,53,54,54,54,54,55,55,55,55,55,55,56,56,56,56,56,56,57,57,57,57,58,57,58,58,58,58,58,58,59,59,59,59,60,60,60,60,60,60,61,60,61,61,61,61,61,61,62,60,59,60,62,59,60,58,88,59,60,59,60,63,62,62,62,63,63,63,62,62,61,90,91,92,63,92,63,92,62,93,61,61,95,60,94,94,62,63,62,80,65,65,65,82,65,65,82,82,66,66,67,67,83,68,84,67,66,65,84,83,64,65,69,69,67,68,68,68,68,68,69,70,66,69,67,67,71,70,71,71,71,71,71,72,72,71,71,71,71,71,71,72,73,72,74,75,74,74,74,74,74,75,74,75,74,74,74,74,74,75,75,74,75,74,75,76,75,75,76,75,75,76,75,75,76,75,76,77,76,76,77,77,77,77,77,77,78,77,78,78,78,78,79,78,79,79,79,79,79,64,79,64,64,64,64,64,65,65,65,26,66,25,67,24,67,23,68,22,31,29,27,24,22,31,23,218,218,218,218,218,218,218,218,218,218,218,218,217,217,217,217,217,217,221,217,221,221,221,221,221,221,221,221,220,220,220,220,220,219,220,220,220,220,219,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,199,196,196,196,196,193,193,193,193,194,194,199,196,196,196,193,193,194,193,194,193,194,193 +,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,252,107,252,107,252,107,252,107,252,107,252,107,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,109,107,107,107,252,107,252,107,252,107,252,107,252,107,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,107,109,107,107,107,107,101,32,34,37,38,41,42,45,47,102,102,103,103,103,103,103,96,103,103,96,97,96,96,96,97,97,97,97,99,98,99,98,98,97,103,99,98,99,99,99,100,99,99,99,47,99,103,100,102,101,100,103,101,100,100,51,101,102,101,101,102,102,103,102,102,102,102,101,49,49,101,51,101,101,50,102,102,102,100,51,51,98,52,97,52,52,52,52,52,49,49,98,50,51,50,50,102,50,49,50,46,50,50,100,50,51,50,50,50,51,51,102,51,51,51,51,51,102,102,51,102,51,50,51,51,51,50,48,48,54,51,51,50,51,50,50,50,53,51,52,51,52,52,53,52,53,53,54,53,54,53,54,54,54,54,55,54,55,55,56,55,56,56,57,56,57,57,57,57,58,57,58,58,59,58,59,58,59,59,60,59,60,60,61,60,61,61,61,62,61,60,62,60,61,60,62,62,62,61,62,60,59,59,61,59,60,62,60,58,88,59,61,64,62,61,62,63,62,89,89,90,63,91,91,62,91,92,92,92,93,93,94,63,94,62,94,80,80,95,62,95,65,66,65,64,66,66,65,64,65,65,66,68,68,69,68,69,68,68,69,68,67,67,69,71,67,70,70,69,71,70,70,71,72,71,70,69,73,70,71,72,71,72,72,72,72,72,72,72,73,73,73,73,73,74,74,74,74,75,74,74,75,74,75,75,74,75,75,75,75,75,74,75,75,75,75,75,75,75,76,76,75,76,77,76,77,76,76,76,76,76,77,76,77,77,78,77,78,77,78,78,79,78,79,78,79,78,79,79,79,64,79,29,79,64,64,27,65,27,66,30,66,29,67,28,67,27,68,27,69,26,218,25,30,24,27,23,24,22,218,218,218,218,218,218,218,218,218,218,218,217,218,217,217,217,217,221,217,221,217,221,221,221,221,221,221,220,221,220,221,220,220,220,220,219,220,219,220,219,220,219,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,199,196,196,196,196,193,196,193,194,194,194,199,196,196,196,193,196,194,193,194,193,194,194,194 +,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,107,107,107,107,107,252,107,109,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,107,107,107,252,109,109,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,107,109,107,252,107,107,107,107,101,102,102,102,102,102,102,102,102,103,103,102,102,103,103,47,32,36,39,43,47,99,97,98,97,98,97,98,98,100,98,100,99,101,96,100,96,99,101,51,97,96,51,99,47,102,100,103,101,102,102,102,102,51,52,99,51,102,103,103,102,102,103,102,102,52,52,102,101,102,101,51,51,102,50,51,51,102,52,52,52,53,52,53,52,52,97,51,50,51,96,50,50,51,102,50,101,50,50,100,50,50,50,50,50,51,51,51,51,51,52,102,52,53,52,52,52,52,52,52,52,52,51,51,52,51,51,51,51,51,51,54,51,51,52,51,54,52,52,52,52,53,53,53,53,53,53,54,54,54,54,55,55,55,55,56,56,56,56,57,57,57,57,58,58,58,58,58,58,59,59,59,59,60,60,60,60,61,61,61,61,61,62,62,62,62,62,62,62,63,61,63,62,62,62,62,84,62,84,62,63,61,61,62,60,60,60,60,60,59,60,89,69,61,88,63,69,62,90,90,88,90,90,63,91,63,91,92,93,94,63,94,94,94,64,94,95,81,64,66,65,65,66,65,66,66,67,67,68,67,67,68,69,68,68,68,69,68,69,70,71,72,71,71,70,72,70,72,71,73,71,70,71,71,71,72,72,73,72,73,72,72,72,73,72,73,73,73,74,72,73,73,73,74,75,73,74,74,75,75,75,75,75,76,75,75,76,75,75,75,75,75,75,76,76,75,76,75,76,75,76,76,76,77,76,76,77,77,76,77,77,77,77,78,78,78,78,78,78,78,78,79,79,79,30,79,79,79,64,79,64,64,28,64,28,65,27,65,27,66,30,67,29,67,28,68,27,68,26,31,25,27,23,25,22,22,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,217,217,217,217,217,221,221,221,221,221,221,221,221,220,221,220,220,220,220,220,220,220,220,220,220,219,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,196,196,196,193,196,196,196,193,194,193,194,196,196,196,196,193,193,194,193,194,194,194,194,193,194 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,252,107,252,107,252,107,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,109,109,107,109,107,252,107,107,107,102,101,102,101,102,102,102,102,102,103,103,102,103,102,103,96,97,97,97,97,97,97,97,97,98,96,100,99,98,51,102,100,51,100,103,97,97,51,97,96,47,97,96,101,103,51,101,50,51,50,99,98,102,99,99,52,51,51,102,103,101,53,103,52,103,102,54,102,53,102,102,52,102,54,102,52,52,52,52,52,53,52,52,52,52,52,52,52,52,52,52,52,52,52,52,51,50,50,50,51,50,50,51,50,49,51,52,51,52,52,53,52,53,53,54,53,53,53,53,53,53,53,54,54,54,52,52,51,52,54,51,51,54,51,52,51,51,52,52,53,52,53,53,54,53,54,55,54,55,55,56,56,55,56,56,56,57,57,58,57,58,58,59,58,58,59,58,59,58,60,59,61,61,61,62,61,62,62,62,63,62,61,63,61,61,60,60,62,62,62,63,63,63,63,61,82,62,82,63,59,84,62,85,62,61,60,62,62,62,88,88,62,60,64,88,89,64,64,90,69,91,65,91,91,67,92,91,92,93,64,64,65,64,94,64,64,64,65,65,65,66,67,67,66,67,67,67,67,67,67,68,68,68,69,68,69,69,70,69,69,70,72,71,72,72,72,71,72,71,73,72,71,72,72,73,73,74,73,71,74,73,73,73,73,73,73,73,74,73,74,73,74,75,74,74,74,74,74,74,74,75,75,75,75,75,76,75,75,76,76,75,75,76,75,77,76,76,75,76,77,76,76,76,76,77,77,76,77,77,77,78,77,78,78,78,78,78,78,79,78,79,79,79,79,79,64,79,64,79,64,64,64,65,31,65,30,66,29,66,27,67,27,68,26,68,25,69,23,30,23,31,22,31,23,29,30,26,28,24,26,218,25,218,23,218,22,218,218,218,218,218,218,218,218,218,217,218,217,217,221,217,221,217,221,221,221,221,220,221,220,221,220,221,220,221,220,220,220,220,219,220,219,220,219,220,219,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,196,196,196,193,196,194,196,194,194,193,194,194,199,196,196,193,196,194,193,194,193,194,193,194,194,194 +,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,107,107,107,107,107,107,107,107,107,109,107,252,252,252,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,109,107,109,107,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,109,107,107,107,109,107,107,107,107,107,102,101,102,102,102,102,103,103,103,102,96,103,96,103,97,96,97,98,103,97,99,100,98,53,98,99,98,97,97,99,97,100,99,97,102,52,97,102,51,101,51,101,51,51,103,50,50,98,99,99,51,98,51,102,96,52,53,53,102,53,53,52,102,102,102,102,53,52,53,52,52,52,52,53,52,52,53,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,53,53,53,53,53,53,54,55,55,54,56,55,56,51,58,52,56,56,54,58,51,54,54,52,51,53,52,52,53,53,55,54,55,55,55,56,56,57,57,57,57,55,57,56,58,58,59,59,60,60,60,61,61,59,61,59,61,62,58,62,60,60,60,61,61,62,62,63,63,62,62,63,62,62,62,62,62,62,62,95,63,80,62,82,63,83,84,84,61,59,85,59,60,60,62,59,63,90,60,62,64,61,66,67,65,68,71,68,68,69,65,65,66,69,67,65,65,65,66,66,66,66,66,66,66,65,66,66,66,67,67,67,67,67,67,68,67,67,68,68,68,69,69,69,69,71,69,70,71,70,71,72,71,72,72,72,73,73,72,73,73,73,72,74,72,73,72,73,74,74,74,74,73,73,73,74,74,73,75,74,74,74,74,74,74,74,74,74,75,75,75,75,75,75,75,75,76,76,76,76,76,77,77,76,77,76,76,77,76,78,77,76,77,76,77,78,77,78,78,78,78,78,78,79,79,79,79,79,79,79,79,79,64,64,64,64,64,64,64,65,28,65,28,66,27,66,27,67,26,67,26,68,26,68,25,69,25,79,31,31,29,26,26,24,31,23,29,22,26,218,24,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,217,217,217,217,217,217,221,221,221,221,221,221,221,221,221,221,220,220,220,220,220,220,220,220,220,220,219,220,219,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,196,196,196,193,196,194,196,194,193,194,194,194,196,193,196,196,196,194,193,194,194,194,194,194,197,194,194 +,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,108,107,107,107,252,107,252,107,252,107,252,107,252,107,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,107,252,107,252,107,252,107,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,109,107,109,109,107,109,107,107,107,109,101,102,101,102,101,102,103,103,103,103,96,103,103,96,97,97,97,52,97,98,97,103,53,52,47,101,52,99,97,52,99,52,46,52,46,52,52,52,52,54,53,54,54,51,51,50,51,102,52,53,53,49,52,52,53,53,53,50,103,102,52,102,102,53,102,52,102,52,53,53,52,53,53,53,53,53,53,53,53,53,52,53,52,53,52,53,52,53,52,53,52,53,52,53,52,53,52,53,52,53,52,53,52,53,53,53,52,53,53,53,53,53,53,53,54,54,54,54,54,55,56,55,56,57,56,54,57,54,56,58,56,57,53,56,58,53,52,55,53,54,55,53,55,55,57,58,57,58,58,58,58,57,58,57,59,59,57,60,58,61,59,62,63,63,61,61,61,59,60,63,59,60,63,63,63,60,60,60,63,63,92,62,93,63,63,61,63,81,62,63,95,81,63,63,80,83,82,84,85,84,64,60,64,64,84,62,86,86,64,69,59,86,67,68,67,68,67,70,71,73,75,67,69,70,68,69,66,66,69,66,71,68,67,68,67,66,66,67,67,67,67,67,67,68,68,68,68,68,68,69,69,69,68,69,69,69,70,69,69,70,71,71,71,72,72,72,72,73,73,72,73,73,73,73,74,73,74,73,74,74,74,74,74,73,74,73,74,75,74,75,73,74,75,75,74,74,74,75,74,75,76,75,76,75,75,75,76,76,77,76,77,76,77,77,77,77,76,77,78,77,78,77,77,77,78,78,77,78,78,79,78,79,78,79,79,79,79,79,64,79,64,79,64,79,64,64,64,65,64,65,65,66,27,66,27,67,27,67,30,68,29,68,28,69,27,69,26,70,25,79,24,27,23,25,22,24,23,22,22,218,22,218,31,218,26,218,22,218,218,218,218,218,218,218,218,218,218,218,217,218,217,217,217,217,221,217,221,217,221,221,221,221,220,221,220,221,220,221,220,221,220,220,220,220,219,220,219,220,219,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,196,196,193,196,194,193,194,193,194,193,194,196,193,196,193,196,194,193,194,193,194,193,194,197,194,197,194 +,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,107,108,107,107,107,107,107,108,107,252,107,109,107,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,107,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,109,107,109,109,109,107,109,107,107,109,101,102,101,52,103,102,52,103,103,102,52,103,96,52,96,52,97,97,52,98,52,96,52,96,52,103,96,52,102,99,52,52,54,54,101,52,53,52,54,101,54,53,52,53,52,53,53,49,52,96,52,52,52,53,53,53,102,53,52,54,102,52,52,53,52,102,53,52,53,52,53,52,53,53,53,53,53,53,53,52,53,53,53,52,53,53,53,52,53,53,53,52,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,54,54,54,54,54,55,55,55,55,55,55,55,56,56,56,56,58,54,52,53,56,59,52,52,56,54,56,55,57,54,56,57,59,60,59,60,58,63,57,63,57,62,58,62,57,89,58,63,58,61,62,61,62,61,62,59,63,62,91,62,60,62,59,61,61,58,92,92,63,92,92,63,63,93,62,81,61,81,62,81,82,82,82,81,82,84,83,84,86,64,65,87,66,87,86,65,65,86,69,66,66,65,64,66,68,69,75,72,73,73,74,68,68,74,73,73,72,69,73,68,72,75,68,68,69,69,69,69,70,68,68,67,67,69,69,70,69,69,70,69,70,69,70,70,70,70,71,71,71,71,70,70,71,72,72,73,72,71,73,72,73,74,73,73,74,73,74,74,74,75,75,74,74,75,74,74,75,74,75,74,75,75,75,75,75,75,75,74,75,76,75,76,76,76,76,76,76,77,76,77,77,77,77,77,77,77,78,77,78,78,78,78,78,78,78,78,78,79,79,79,79,79,79,79,79,79,79,64,64,64,64,64,64,64,64,65,65,65,65,66,66,66,66,66,66,67,23,67,26,68,26,68,25,69,25,69,25,70,24,70,24,27,24,29,23,30,23,218,22,218,30,218,28,218,26,218,24,218,23,218,218,218,218,218,218,218,218,218,218,218,217,217,217,217,217,217,221,217,221,221,221,221,221,221,221,221,221,221,220,221,220,220,220,220,220,220,219,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,196,196,196,196,194,193,194,194,194,194,194,196,193,193,196,196,193,193,194,194,197,197,197,197,197,197,197,197 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,108,107,252,107,109,107,252,107,252,107,252,107,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,252,107,109,107,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,107,107,109,107,109,107,109,107,109,109,101,53,102,102,52,102,53,102,53,53,102,103,53,96,103,52,52,97,52,47,53,54,53,54,53,54,102,52,52,102,53,52,53,54,54,53,53,101,54,54,52,53,52,53,54,53,54,53,54,54,52,53,53,52,53,53,53,50,52,52,52,102,52,53,53,53,53,53,53,53,54,53,54,53,54,53,54,53,54,53,54,53,54,53,54,53,54,53,54,53,54,53,54,53,54,53,54,53,54,53,54,53,54,54,54,54,54,54,55,55,55,55,55,55,55,56,56,56,56,56,56,56,56,56,56,58,52,55,57,58,52,55,58,58,60,57,53,56,59,56,58,55,59,56,63,63,85,63,60,86,60,88,62,90,59,90,59,89,60,61,60,89,63,90,63,62,91,63,92,60,60,63,62,61,60,62,60,92,93,92,92,63,93,93,63,94,63,81,80,65,62,65,81,83,83,83,65,65,65,64,65,65,65,65,66,89,65,88,66,66,68,70,66,68,70,71,71,75,72,70,74,75,73,75,74,73,74,72,68,71,73,72,72,73,71,72,69,68,69,71,72,70,70,71,69,71,70,70,71,71,71,71,70,71,72,71,71,72,71,72,72,71,72,71,71,70,72,72,73,73,72,73,73,73,73,74,74,74,74,74,74,74,75,74,75,75,75,75,74,75,75,75,75,75,76,76,75,75,76,75,75,76,76,76,77,76,77,76,77,76,77,77,78,77,78,77,78,77,78,78,79,78,79,78,79,78,79,79,79,64,79,64,79,64,79,64,79,64,64,64,64,64,65,28,65,28,65,65,66,30,66,30,67,29,67,28,68,27,68,27,69,26,69,25,70,24,70,24,71,23,71,30,72,28,27,27,28,26,29,24,31,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,217,217,217,221,217,221,217,221,217,221,217,221,221,221,221,220,221,220,221,220,221,220,221,220,220,219,220,219,220,219,220,219,219,219,220,219,219,219,220,219,219,219,220,219,219,219,220,219,196,196,193,196,194,193,194,193,194,194,196,196,196,196,197,196,194,194,194,194,197,197,198,197,198,197,198,197,198 +,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,108,107,108,107,107,107,109,107,109,107,252,107,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,109,107,109,107,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,109,107,109,109,109,107,109,107,107,107,109,109,50,52,102,53,102,53,53,102,98,103,53,98,102,53,53,53,54,53,98,53,54,54,54,54,54,54,54,54,54,54,54,54,55,101,55,54,55,55,54,54,54,53,53,53,54,53,54,55,54,55,101,55,55,52,52,53,52,52,52,53,53,53,53,53,53,53,54,53,53,53,54,53,54,53,54,53,54,53,54,53,54,53,54,53,54,53,54,53,54,53,54,54,54,54,54,54,54,54,54,54,54,54,55,54,55,54,55,54,54,55,56,56,56,56,56,56,56,56,56,56,56,57,56,57,57,57,58,58,57,57,57,56,57,55,59,60,59,60,58,63,57,58,62,85,85,86,86,86,62,87,88,89,90,62,90,89,64,60,89,62,89,91,90,62,66,91,92,90,93,91,91,91,92,62,94,63,92,61,92,93,93,95,94,80,94,95,81,81,66,81,67,82,82,65,65,65,68,65,66,66,66,67,66,66,66,66,66,66,66,67,67,67,67,68,70,70,75,72,72,74,75,75,75,73,71,75,72,74,71,71,75,73,73,72,74,73,71,71,72,72,71,71,71,72,71,73,71,71,73,72,72,72,72,72,72,73,72,72,72,72,73,73,71,72,73,71,72,73,72,73,73,73,73,73,74,73,74,74,74,74,74,74,75,74,75,75,75,75,75,75,75,75,76,76,76,76,76,76,76,76,77,77,77,77,77,77,77,77,78,77,78,78,78,78,78,78,79,78,79,79,79,79,79,79,79,30,79,79,79,64,79,29,64,29,64,64,64,64,64,64,65,65,65,65,66,65,66,66,66,66,67,67,67,67,68,68,68,26,69,25,69,25,70,25,70,24,70,24,71,30,71,29,72,27,22,30,218,29,218,27,218,26,218,30,218,28,218,25,218,23,218,218,218,218,218,218,218,218,218,218,218,217,217,217,217,217,217,217,217,221,217,221,221,221,221,221,221,221,221,221,221,220,220,220,220,220,220,220,220,219,220,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,196,196,196,196,194,193,194,193,194,194,196,196,196,196,196,196,197,197,197,197,197,197,197,197,198,197,198,198,198,198 +,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,107,108,107,252,107,252,107,252,107,252,107,107,107,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,109,107,252,107,252,107,252,107,252,109,252,109,252,109,252,109,252,109,252,252,252,109,109,107,109,107,109,107,109,107,107,107,109,52,52,103,102,53,102,98,53,52,53,53,54,53,54,53,98,53,54,54,54,54,54,54,55,54,54,54,55,54,55,54,55,55,55,54,55,55,55,55,55,55,55,55,55,55,54,54,54,55,54,55,55,55,55,55,55,55,53,56,52,53,54,53,53,53,54,54,54,54,54,54,54,54,54,54,54,54,55,54,55,54,55,54,54,54,55,54,55,54,55,54,55,54,55,54,55,54,55,54,55,54,55,55,55,55,55,55,55,55,56,56,57,56,57,56,57,57,57,57,58,57,58,57,58,57,58,58,59,58,58,56,57,57,58,59,56,63,63,85,63,60,84,83,84,83,84,85,86,87,86,88,91,64,65,62,65,92,65,90,91,65,64,92,91,67,92,65,65,65,66,93,67,67,92,65,64,67,63,65,65,93,64,65,66,67,68,80,68,66,81,66,65,64,66,66,66,69,67,67,67,67,70,69,68,68,68,68,67,69,67,68,69,68,66,69,66,70,69,71,68,73,74,75,75,74,75,75,72,74,74,72,72,75,111,111,111,104,104,74,74,72,71,73,74,72,73,73,72,73,73,73,73,73,72,72,72,72,72,72,74,74,73,73,73,73,74,74,74,73,74,74,74,75,74,75,75,74,75,74,75,74,75,75,76,75,76,75,76,75,76,76,76,76,77,76,77,76,77,76,77,77,78,77,78,77,78,77,78,78,79,78,79,78,79,78,79,79,79,79,79,79,79,64,79,64,79,64,79,64,79,29,64,64,64,64,64,30,65,29,65,27,66,25,66,66,67,66,67,66,67,67,68,67,68,68,69,68,69,69,70,69,70,28,70,28,71,27,71,26,72,25,72,24,73,24,29,23,31,22,218,22,218,30,218,28,218,27,218,25,218,24,218,22,218,218,218,218,218,218,218,218,218,217,218,217,217,217,217,221,217,221,217,221,217,221,221,221,221,221,221,220,221,220,221,220,221,220,220,220,221,219,220,219,220,219,220,219,220,219,220,219,220,219,220,219,220,219,196,196,196,196,197,196,194,196,194,194,194,197,196,196,197,196,197,196,197,196,197,197,198,197,198,197,198,197,198,197,198 +,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,107,108,107,108,107,108,107,108,108,252,108,252,108,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,109,109,109,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,109,109,107,109,109,107,109,107,109,107,109,107,109,53,52,53,102,53,52,53,98,53,102,53,54,53,54,54,54,53,54,54,54,54,54,54,55,54,55,54,55,54,55,54,55,55,55,55,55,55,55,56,56,56,56,56,56,55,55,55,55,55,55,55,55,55,55,56,54,54,53,54,56,53,54,54,54,53,55,54,54,54,54,54,55,54,54,54,54,54,55,54,55,54,55,54,55,54,55,54,55,54,55,55,55,55,55,55,55,55,55,55,55,56,56,56,57,57,57,57,57,57,57,57,58,58,58,58,58,58,58,58,59,59,59,59,59,59,59,59,60,63,63,62,62,84,58,62,85,85,86,86,86,83,84,83,84,84,85,85,85,85,88,88,91,91,92,92,64,66,64,65,64,66,65,67,65,66,65,67,66,68,67,67,67,66,65,66,65,92,68,65,66,66,67,68,68,69,66,67,66,68,64,67,66,66,67,69,69,67,69,69,69,69,69,70,69,69,68,69,68,69,70,69,70,71,69,67,67,70,67,71,71,73,75,75,74,105,105,105,105,105,105,111,111,110,110,110,110,110,104,76,72,73,74,74,74,73,75,74,73,74,73,74,73,74,74,74,74,74,74,74,74,74,74,75,74,75,74,75,75,75,75,75,75,75,75,75,75,75,75,75,76,75,76,76,76,76,76,76,76,76,77,77,77,77,77,77,77,77,78,77,78,77,78,78,78,78,78,78,78,78,79,79,79,79,79,79,79,79,79,79,79,64,79,64,64,64,64,64,64,64,64,64,64,64,65,65,65,65,66,66,66,27,67,27,67,27,67,27,68,26,68,26,68,26,69,26,69,25,70,25,70,25,71,24,71,24,71,31,72,30,72,29,72,28,28,31,29,30,30,28,31,27,218,26,218,24,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,217,217,217,217,217,217,217,217,221,217,221,221,221,221,221,221,221,221,221,221,220,220,220,220,220,220,220,220,219,219,219,219,219,219,219,219,219,219,219,219,219,196,196,196,196,197,196,197,197,194,194,194,194,196,196,196,196,197,197,197,197,197,197,197,197,198,197,198,198,198,198,198,198 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,107,252,107,108,107,252,107,252,108,252,108,252,108,109,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,252,107,252,107,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,109,107,109,107,109,107,109,107,107,107,109,107,109,101,52,53,53,101,53,53,103,53,54,54,54,54,54,54,55,54,55,54,55,55,55,55,55,55,55,55,55,55,55,55,55,55,56,56,57,56,57,56,57,57,57,57,58,58,56,56,56,56,56,55,55,55,55,57,57,57,58,58,58,56,55,55,55,55,55,54,54,55,55,55,55,54,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,56,57,56,57,56,57,57,58,57,58,57,58,57,58,58,58,58,59,58,59,58,59,59,59,59,59,59,60,59,60,60,60,60,60,60,60,60,61,63,83,83,83,83,63,84,83,84,83,84,85,86,84,83,84,85,84,86,85,86,86,88,88,89,89,89,65,64,66,65,64,65,65,65,66,66,66,67,66,68,68,67,68,68,68,67,69,68,68,68,69,69,66,68,70,69,69,68,70,68,69,69,67,69,68,70,70,69,69,68,70,70,70,70,69,68,70,69,71,69,70,71,72,72,72,72,71,69,105,105,105,105,105,105,105,105,111,110,111,105,105,111,111,110,110,110,111,110,111,110,104,104,74,75,76,74,75,75,75,75,75,74,75,75,74,74,74,74,75,75,76,76,75,75,75,75,75,75,76,76,75,75,75,75,76,76,76,75,76,75,76,76,77,76,77,76,77,76,77,76,77,77,78,77,78,77,78,77,78,78,78,78,78,78,79,78,79,78,79,78,79,79,79,64,79,64,79,64,79,64,79,64,79,29,79,64,64,64,64,28,65,28,65,28,65,28,66,27,66,27,67,27,67,67,68,67,68,67,68,68,69,68,69,68,69,28,70,27,70,26,71,25,71,24,72,23,72,23,72,22,73,23,73,23,27,23,28,22,28,22,29,22,30,22,31,22,218,31,218,29,218,27,218,25,218,23,218,22,218,218,218,218,218,218,218,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,220,221,220,221,220,220,220,220,219,221,219,220,219,220,219,220,219,220,219,220,219,220,196,196,196,197,196,194,197,194,194,198,197,196,196,197,196,197,196,197,196,197,197,198,197,198,197,198,197,198,197,198,197,198 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,107,108,107,108,107,108,107,108,108,109,108,252,108,108,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,109,107,109,107,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,109,109,109,109,107,109,107,109,107,107,107,109,109,54,53,54,53,54,53,54,53,54,53,54,53,54,54,54,54,54,55,54,55,54,55,54,55,55,55,55,55,55,55,55,56,56,56,56,56,56,57,57,57,57,57,57,57,57,58,58,58,57,58,58,58,55,56,56,56,57,57,57,57,57,58,58,56,56,56,56,56,55,55,55,55,55,55,55,56,56,56,56,56,57,57,57,57,57,57,57,57,58,58,58,58,58,58,58,58,59,58,59,59,59,59,59,59,60,59,60,60,59,60,60,60,59,60,60,60,61,61,61,61,61,61,61,62,83,81,82,83,82,82,83,82,83,84,83,84,84,85,85,85,85,85,86,86,87,86,87,86,87,87,89,64,64,89,64,64,64,66,64,65,65,65,65,66,66,67,66,66,67,67,67,67,68,68,69,68,68,68,69,69,69,69,69,70,69,68,70,70,71,69,69,69,69,70,69,70,70,69,70,70,71,70,70,71,71,72,71,71,72,72,105,105,105,105,105,105,105,105,110,110,110,110,111,111,111,111,105,110,110,110,110,110,110,110,111,110,111,104,111,104,76,76,76,76,75,76,76,76,75,75,76,75,76,76,75,75,76,76,76,76,76,77,76,77,76,76,76,76,76,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,78,77,78,77,78,78,78,78,78,78,78,78,79,79,79,79,79,31,79,79,79,79,79,64,79,64,79,64,64,64,64,64,64,64,64,30,64,29,65,28,65,27,65,26,66,25,66,66,67,67,67,67,67,67,68,26,68,26,68,68,69,69,69,69,70,70,70,70,70,70,71,71,71,24,71,31,72,29,72,26,73,31,78,30,79,29,218,28,218,27,22,26,25,25,28,25,31,24,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,217,217,217,217,217,217,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,220,221,220,220,220,220,220,220,219,219,219,219,219,219,219,219,219,219,196,196,197,197,196,197,194,196,197,198,196,196,196,196,196,197,196,197,197,197,197,197,197,198,197,198,198,198,198,198,198,198,198 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,107,108,107,252,107,252,107,252,107,252,108,252,108,252,108,109,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,109,107,252,107,252,107,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,109,109,109,107,109,107,109,107,107,107,109,107,109,54,53,54,53,54,53,54,54,54,54,54,54,54,55,55,55,54,55,55,55,55,55,55,55,55,56,55,56,56,56,56,57,56,57,57,57,57,58,57,58,57,58,58,59,58,59,58,59,59,58,58,58,58,58,58,57,58,58,58,57,57,57,57,58,58,58,57,58,58,58,55,56,56,56,56,57,57,57,57,58,57,58,57,58,57,58,58,58,58,59,58,59,58,59,59,59,59,60,59,60,59,60,60,60,60,61,60,60,61,60,58,60,61,61,60,59,60,61,82,61,63,82,82,82,82,82,82,82,82,82,83,83,84,83,84,85,84,86,85,86,86,64,64,64,64,87,64,88,65,64,65,65,64,65,65,65,65,65,66,65,66,66,66,65,66,65,66,66,66,67,67,67,68,68,68,69,68,68,69,69,70,69,69,70,71,70,71,70,71,70,70,71,70,71,71,72,71,71,71,71,70,70,71,71,72,71,71,72,105,105,105,111,105,111,105,105,110,110,110,111,110,111,110,111,111,105,110,110,110,111,110,111,110,111,110,111,104,106,104,106,106,75,75,76,76,76,75,76,76,76,76,76,77,77,76,76,76,77,77,77,77,76,76,77,76,77,76,77,77,77,77,77,77,77,77,77,77,77,77,78,77,78,77,78,77,78,77,78,78,78,78,79,78,79,78,79,78,79,79,79,79,79,64,79,64,79,64,79,64,79,64,79,64,64,64,64,64,64,64,65,64,65,65,65,22,66,28,66,27,66,27,67,27,67,27,68,26,68,26,68,30,69,29,69,28,69,27,70,27,70,26,71,25,71,24,71,23,72,22,72,24,72,24,73,23,73,23,78,23,78,23,79,23,79,22,218,22,218,22,218,22,218,31,218,29,218,27,218,26,218,24,218,22,218,218,218,218,218,218,218,218,218,217,218,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,221,221,220,221,220,221,220,221,220,221,220,220,220,220,220,196,196,196,196,196,196,196,196,196,197,196,197,194,197,198,196,197,196,197,196,197,196,197,196,197,197,198,197,198,197,198,197,198,197,198,198,198,198,198 +,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,108,107,108,107,108,107,108,107,109,107,108,108,252,108,109,108,252,108,108,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,109,109,109,109,252,109,109,109,252,252,252,109,252,252,252,252,252,252,252,109,109,109,109,107,109,107,109,107,107,107,109,107,109,54,53,54,53,54,53,54,54,54,54,54,54,54,55,55,55,54,55,55,55,55,55,55,55,55,56,55,56,56,56,56,57,56,57,57,57,57,58,57,58,57,58,58,59,58,59,58,59,59,59,59,58,59,59,59,58,57,58,58,58,59,58,59,58,59,59,58,58,58,58,58,58,57,58,57,57,57,58,58,58,58,58,58,58,58,59,59,59,59,59,59,59,59,60,60,60,60,60,60,61,60,61,61,61,61,61,60,61,60,60,58,61,61,60,61,59,61,82,82,82,82,82,82,82,82,82,82,82,82,82,82,83,83,83,84,85,84,85,65,65,86,65,65,65,64,65,65,65,65,65,66,65,66,65,66,67,66,66,66,66,66,66,66,66,66,66,66,66,66,66,67,67,67,67,68,68,68,68,68,68,70,69,70,70,70,71,71,71,71,71,71,71,70,71,71,72,71,70,71,71,71,71,72,71,72,105,105,105,111,111,111,111,105,111,110,110,110,110,110,111,111,111,111,105,110,110,110,110,110,110,110,111,110,111,104,111,111,104,106,106,76,76,75,75,76,76,77,76,76,76,76,77,76,76,76,76,76,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,78,77,78,78,78,78,78,78,78,78,79,79,79,79,79,79,79,31,79,79,79,30,79,30,79,64,79,64,64,64,64,64,64,64,64,64,64,64,65,28,65,28,65,28,66,28,66,66,66,27,67,27,67,27,67,27,68,26,68,26,68,26,69,26,69,26,70,26,70,25,70,25,70,25,71,25,71,24,72,24,72,30,72,29,73,28,73,31,73,29,78,29,79,28,79,27,218,26,218,25,218,24,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,217,217,217,217,217,217,217,221,217,221,221,221,221,221,221,221,221,221,221,220,220,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,197,197,196,196,194,194,198,196,196,196,196,196,197,196,197,197,197,197,197,197,198,197,198,197,198,198,198,198,198,198,198,198 +,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,109,252,252,107,109,107,252,107,109,107,109,108,252,108,109,108,252,108,108,108,109,252,252,108,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,107,107,107,109,107,109,107,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,109,109,109,109,107,109,107,107,107,109,107,109,109,54,54,54,55,54,55,54,55,54,55,54,55,54,55,54,55,55,55,55,55,55,55,56,55,56,57,56,56,56,56,57,57,57,57,57,57,58,58,58,58,58,58,59,58,59,59,59,59,59,59,59,59,58,59,59,59,58,58,57,58,58,59,58,59,58,59,59,59,59,58,59,59,59,58,57,58,59,58,59,58,59,58,59,60,60,60,59,59,59,60,61,61,60,61,60,61,61,61,62,61,62,62,62,62,62,61,61,61,60,60,82,82,59,82,61,82,82,81,61,61,82,61,82,82,82,82,82,82,82,83,64,82,83,83,84,84,83,64,65,64,64,64,64,65,66,65,66,66,66,66,66,65,67,65,66,67,66,67,67,68,67,67,66,67,67,67,67,67,67,67,67,67,68,67,68,67,68,67,69,69,69,70,70,69,69,70,70,70,70,71,71,72,71,71,72,72,71,72,73,72,71,72,71,105,105,105,111,110,111,110,111,105,110,110,110,110,111,110,111,110,111,110,105,110,111,110,110,110,111,110,111,110,111,104,111,106,104,107,107,106,106,75,76,76,76,76,76,77,77,77,77,76,77,76,77,76,77,78,77,77,78,78,77,78,77,78,77,78,78,77,77,78,78,77,77,78,78,77,78,78,79,78,79,78,79,78,79,79,79,79,79,79,79,64,79,64,79,64,79,64,79,64,79,64,79,64,64,64,64,64,65,64,65,28,65,28,66,28,66,28,66,27,67,66,67,66,67,67,68,67,68,68,68,68,69,29,69,28,69,27,70,25,70,25,70,24,71,31,71,30,71,29,72,28,72,27,72,26,73,25,73,24,73,23,74,22,74,22,74,31,31,29,218,28,218,27,218,25,218,24,218,30,218,28,218,27,218,25,218,24,218,22,218,218,218,218,218,218,218,217,218,217,217,217,217,221,217,221,217,221,217,221,217,221,221,196,196,196,196,196,196,196,196,196,196,196,197,197,196,196,197,196,197,197,198,197,198,198,197,197,196,196,196,196,197,197,194,197,198,196,196,196,197,196,197,196,197,196,197,197,198,197,198,197,198,197,198,198,198,197,198,198,198,198,198 +,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,109,252,108,107,108,107,108,107,109,107,109,108,252,108,109,108,252,252,252,108,108,252,109,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,109,107,109,109,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,109,109,107,109,107,109,107,107,107,109,109,109,54,54,54,55,54,55,54,55,54,55,54,55,54,55,54,55,55,55,55,55,55,55,56,55,56,57,56,56,56,56,57,57,57,57,57,57,58,58,58,58,58,58,59,58,59,59,59,59,59,59,59,59,59,59,59,59,59,59,58,58,59,58,59,59,59,59,59,59,59,59,58,59,59,59,58,58,58,59,59,59,58,60,60,58,60,60,60,60,59,60,61,61,62,60,61,61,62,61,62,62,63,63,63,62,61,61,62,81,82,82,82,61,63,82,60,61,82,61,82,84,84,82,82,82,82,84,82,82,82,65,65,65,64,66,64,64,65,65,65,67,65,65,67,65,66,66,65,66,66,66,66,66,66,67,67,67,67,67,67,67,67,67,68,68,67,68,68,68,68,68,68,68,68,68,68,68,68,69,69,69,69,69,69,69,69,69,70,70,70,70,70,71,71,71,71,72,71,72,72,71,72,105,105,105,110,111,111,111,111,111,105,111,110,110,110,111,110,111,111,111,111,111,110,110,110,110,110,110,110,111,110,111,104,111,106,108,104,107,106,106,106,106,76,76,76,76,76,76,76,77,77,77,77,77,77,77,77,77,77,77,78,77,78,77,78,78,78,78,78,78,78,78,78,78,78,78,78,79,78,79,79,79,79,79,79,79,79,79,79,79,79,79,64,79,64,79,64,64,64,64,64,64,64,64,64,64,64,64,64,65,65,65,27,65,65,66,66,66,66,66,66,67,67,67,67,67,22,68,27,68,26,68,26,69,69,69,69,69,26,70,25,70,25,70,25,71,25,71,25,71,25,72,24,72,24,72,24,73,24,73,31,73,30,73,28,74,27,74,25,31,24,31,23,218,31,218,30,218,28,218,27,218,26,218,25,218,24,218,22,218,218,218,218,218,218,218,218,218,218,218,217,217,217,217,217,217,221,217,221,221,221,221,221,196,196,196,196,197,197,197,197,197,197,197,197,196,196,196,196,197,197,197,197,197,197,198,198,198,196,196,196,197,197,197,197,194,198,198,196,196,196,196,196,197,196,197,197,197,197,197,197,197,197,198,198,198,198,198,197,198,197,198,198,198,198 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,109,252,109,107,252,107,252,107,109,108,252,108,109,108,252,108,252,108,252,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,107,109,107,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,109,109,109,107,109,107,109,107,109,107,109,109,55,54,55,54,55,54,55,54,55,55,55,55,55,55,55,55,57,56,55,56,55,56,56,57,57,58,58,57,57,58,57,58,57,58,58,59,58,59,58,59,59,60,59,60,59,60,60,60,61,59,59,59,59,59,59,59,59,59,59,58,59,58,59,59,59,59,59,59,59,59,59,59,59,59,59,59,58,59,61,60,59,61,59,60,60,60,59,59,60,61,61,61,61,62,62,63,62,63,63,63,62,62,61,63,63,63,61,61,82,82,65,80,82,62,82,63,61,82,64,64,83,82,82,84,60,60,64,64,66,66,67,66,67,66,66,65,65,65,66,67,66,67,66,67,67,68,67,67,67,66,67,66,66,66,67,67,67,68,68,68,68,67,68,68,68,68,68,69,68,69,69,69,69,68,69,69,69,69,70,69,70,69,70,69,70,70,70,70,71,70,71,70,71,70,71,70,71,71,71,105,105,105,111,110,111,111,111,111,111,105,111,110,111,110,111,110,111,110,111,110,111,111,110,110,111,110,111,110,111,110,111,110,111,106,108,108,104,107,107,106,106,106,76,76,76,76,77,77,76,77,76,77,76,77,77,77,77,78,78,77,77,78,78,77,78,77,78,77,78,78,79,78,79,78,79,78,79,79,79,79,79,79,79,64,79,64,79,64,79,64,79,64,79,64,79,64,64,64,64,29,64,29,65,28,65,28,65,28,65,28,66,65,66,66,66,27,67,27,67,27,67,27,68,27,68,26,68,26,69,26,69,26,69,26,70,25,70,25,70,30,70,30,71,29,71,29,77,28,77,28,77,27,78,27,73,26,73,26,73,25,74,25,74,24,74,24,218,30,218,28,218,26,218,24,218,22,218,31,218,29,218,28,218,26,218,25,218,24,218,22,218,218,218,218,218,218,218,217,218,217,217,217,217,221,217,221,217,221,217,221,221,196,196,196,196,196,197,196,196,196,197,196,197,196,197,196,196,196,197,196,197,196,197,197,198,197,196,196,197,196,197,196,197,197,198,197,198,198,196,196,197,196,197,196,197,196,197,197,197,197,198,197,198,197,198,197,198,198,198,198,196,198,198,198,198 +,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,108,252,108,107,108,107,109,107,108,107,252,252,109,108,252,252,252,108,108,108,252,252,109,252,109,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,109,109,109,109,252,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,109,109,109,109,107,109,107,107,107,109,109,109,107,55,55,55,55,55,55,55,56,57,56,57,56,57,57,58,58,58,56,56,57,56,57,57,59,57,58,59,58,58,58,58,59,59,59,59,60,60,60,60,60,60,61,60,61,61,61,61,61,61,61,59,59,59,61,59,59,59,59,59,59,60,59,60,60,60,61,59,59,59,59,59,59,59,59,59,61,61,61,62,60,59,60,62,59,60,58,59,59,60,59,60,63,62,62,63,62,63,63,81,63,63,61,63,82,61,64,64,64,64,63,65,63,82,82,82,65,64,64,83,63,65,83,83,66,83,65,65,66,67,67,66,67,66,67,68,66,67,67,70,67,67,68,69,68,68,67,68,67,69,67,67,66,67,66,67,67,66,68,67,68,68,68,68,68,68,69,69,69,69,70,71,70,70,70,70,70,70,70,70,70,70,70,71,70,71,70,71,71,71,71,71,71,71,71,72,72,105,105,105,111,111,111,111,111,111,111,111,111,111,110,110,110,110,110,111,111,111,111,111,111,110,110,110,110,110,110,111,111,111,111,111,106,107,108,104,107,107,107,107,106,106,106,76,76,76,77,77,77,77,77,77,77,77,77,77,77,77,77,78,78,78,78,78,78,78,78,79,78,79,78,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,64,79,64,79,64,79,64,79,64,79,64,79,64,64,64,65,65,65,65,66,66,66,66,66,66,66,66,67,67,67,27,68,26,68,26,68,25,68,25,69,24,69,24,69,23,70,23,70,22,70,25,71,25,71,25,71,25,71,24,78,24,78,24,78,24,79,31,79,30,27,29,29,28,31,27,218,26,218,31,218,29,218,30,218,29,218,28,218,27,218,25,218,24,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,217,217,217,217,217,221,217,221,221,221,221,221,196,196,196,196,197,196,196,196,196,196,197,196,196,196,197,197,196,196,196,196,197,196,196,196,196,196,197,197,197,197,197,197,197,197,198,198,198,198,196,196,196,196,197,196,197,196,197,197,197,197,197,197,198,197,198,198,198,198,198,198,198,198,198,198,198,198 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,252,252,107,109,107,109,107,109,108,252,108,252,108,252,108,252,108,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,107,109,107,252,107,109,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,109,109,109,107,109,107,109,107,107,107,109,109,109,55,55,55,55,55,55,56,57,56,57,56,57,57,58,58,58,56,56,57,56,57,57,59,57,58,59,58,58,58,58,59,59,59,59,60,60,60,60,60,60,61,60,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,59,59,59,59,59,59,61,61,61,61,61,59,59,59,61,59,62,62,62,61,62,60,59,59,61,59,60,62,60,58,59,59,90,91,92,61,92,63,62,63,62,63,62,94,94,82,80,80,94,80,94,80,65,81,82,65,65,82,82,66,66,67,67,83,68,84,67,66,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,69,70,70,71,69,68,69,69,68,68,69,68,69,68,67,67,68,68,67,68,69,69,68,69,68,69,70,70,71,71,70,71,70,70,70,71,71,70,71,70,70,71,72,72,71,71,72,71,72,72,72,71,72,105,105,105,111,111,111,111,111,111,111,111,111,111,111,110,110,110,111,110,111,110,111,110,111,111,111,110,111,110,111,110,111,111,111,111,111,104,106,107,104,107,108,107,107,106,107,106,106,106,76,77,77,77,77,77,77,77,78,77,78,77,78,77,78,78,79,78,79,78,79,78,79,79,79,79,79,79,79,64,79,79,79,30,79,30,79,30,79,30,79,31,79,30,79,29,64,29,64,28,64,28,65,27,65,27,66,26,66,25,66,25,66,24,67,24,67,23,67,22,67,22,68,26,68,26,68,26,69,26,69,31,69,30,70,29,70,29,70,28,70,27,71,26,71,26,71,25,72,24,72,23,72,30,67,29,73,28,79,27,26,26,28,24,29,23,30,22,31,23,218,31,218,29,218,27,218,26,218,24,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,217,217,217,221,217,221,217,221,221,196,196,196,196,196,197,196,196,196,197,196,197,196,197,196,197,198,197,196,196,196,197,196,197,196,197,196,197,197,197,197,197,197,198,197,198,197,198,197,198,196,196,196,196,196,197,196,197,197,197,197,197,197,198,197,198,198,198,198,198,198,198,198,198,198,198,196,196 +,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,108,252,108,252,108,107,109,107,108,107,109,108,109,108,109,252,252,252,252,252,108,108,252,252,109,252,109,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,109,107,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,107,109,107,109,107,109,109,109,107,107,57,57,57,57,58,58,58,58,58,58,58,57,57,59,59,57,57,58,57,58,59,59,58,59,59,60,59,60,60,61,60,61,61,61,62,61,60,62,60,61,60,62,62,62,61,62,62,61,61,61,61,61,61,94,61,61,61,59,59,61,59,61,61,61,61,59,59,63,61,63,62,62,84,84,62,62,62,62,63,61,61,62,60,60,60,60,60,59,91,61,91,92,92,92,93,93,94,94,63,94,63,62,65,63,63,80,63,63,63,64,66,66,65,64,65,65,66,68,68,69,68,69,105,105,105,105,105,110,105,105,110,110,110,111,110,111,111,111,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,68,69,69,69,69,70,69,70,70,70,71,71,72,70,71,70,71,71,71,71,71,71,72,71,71,72,72,72,72,72,72,72,71,72,105,105,111,105,111,111,111,111,111,111,111,111,111,111,111,110,110,110,110,110,111,111,111,111,111,110,110,110,111,111,111,110,111,111,111,111,111,111,111,104,106,106,107,107,107,107,107,106,106,106,106,77,77,77,77,77,78,78,78,78,78,78,78,78,78,78,79,78,79,79,79,79,79,79,79,79,79,79,79,79,79,31,64,30,64,30,64,29,64,28,64,27,65,27,65,26,65,26,65,29,65,29,65,28,65,28,66,28,66,28,66,28,66,28,67,27,67,27,67,27,68,27,68,27,68,27,68,26,69,26,69,26,69,26,70,26,28,26,30,25,71,25,71,25,71,25,71,25,72,25,72,24,72,24,73,24,27,24,28,24,28,30,29,29,30,28,30,26,31,25,31,24,218,23,218,31,218,29,218,28,218,27,218,25,218,24,218,23,218,218,218,218,218,218,218,218,218,218,218,217,217,217,217,217,217,217,217,221,221,221,196,196,196,196,196,196,196,196,197,196,196,196,196,196,196,196,197,197,198,198,196,196,196,196,196,196,197,197,197,197,197,197,197,197,197,197,197,197,198,198,198,198,198,198,196,196,196,196,197,197,197,197,197,197,197,197,198,198,198,198,198,198,198,198,198,198,196,196,196,196,196,196 +,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,109,107,109,107,252,107,109,108,252,108,252,108,252,108,252,108,252,108,252,108,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,107,109,107,109,107,107,107,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,109,109,107,109,107,109,107,107,107,109,109,109,107,107,58,59,58,59,58,59,59,58,59,59,59,59,59,58,59,59,60,60,94,60,61,61,58,59,59,60,59,60,60,61,60,61,61,61,62,61,60,62,60,61,60,62,62,62,61,62,62,62,62,61,62,62,62,94,61,61,81,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,84,84,63,59,83,62,62,64,61,60,66,62,64,62,62,85,60,63,91,92,93,94,63,94,94,63,64,94,95,95,66,65,64,65,66,65,66,66,67,67,68,67,67,68,105,105,105,105,105,105,105,105,105,105,110,110,111,110,111,110,111,111,105,105,105,105,105,110,111,110,111,110,111,111,110,109,105,110,111,110,111,105,105,105,71,70,70,70,70,70,70,71,71,71,72,71,72,71,72,71,72,72,72,71,72,72,72,72,73,72,73,72,73,72,73,105,105,111,111,105,111,111,111,111,111,111,111,111,111,111,111,110,110,110,111,110,111,111,111,111,111,110,111,111,111,111,111,110,111,110,111,110,111,110,111,104,104,106,107,106,107,107,107,106,107,106,107,106,106,77,78,77,78,78,78,78,79,78,79,78,79,78,79,78,79,79,79,79,79,64,79,64,79,29,79,29,79,28,79,28,64,28,64,27,65,27,65,26,65,26,65,25,66,25,66,24,69,23,70,23,71,22,72,22,73,30,74,30,75,29,77,28,78,28,79,27,26,27,27,26,27,25,28,25,28,24,29,23,30,23,30,22,31,22,71,25,71,25,71,24,71,24,72,24,72,24,72,24,73,24,25,23,26,23,26,23,27,23,28,23,29,31,29,29,30,27,31,26,31,24,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,217,217,217,221,217,221,217,221,221,196,196,198,198,198,198,196,198,197,198,197,198,197,198,197,198,198,196,196,197,196,197,196,197,196,197,196,197,197,197,197,197,197,198,197,198,197,198,197,198,197,198,198,198,196,197,196,197,196,197,196,197,197,198,197,198,197,198,197,198,198,198,197,198,197,198,196,196,196,196,196,197,197,197 +,108,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,108,252,109,107,108,107,109,107,109,108,109,252,109,108,252,252,252,252,108,108,252,252,252,252,109,252,252,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,109,107,107,107,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,109,109,107,109,107,109,107,107,107,109,107,109,107,59,59,59,59,59,59,60,58,59,58,60,59,61,61,61,62,62,60,60,94,60,61,61,61,61,60,61,61,61,59,58,59,59,60,59,60,60,61,60,61,61,61,62,61,60,62,94,61,60,62,62,93,61,62,61,105,105,105,105,105,105,105,110,110,110,110,110,110,111,111,111,111,110,104,106,61,64,84,83,67,65,67,66,62,67,64,64,85,65,86,65,91,92,93,64,64,65,64,94,64,64,64,65,65,65,66,67,67,66,67,67,67,67,67,105,105,105,110,105,110,105,105,105,109,110,110,110,110,110,110,111,111,111,105,105,109,110,110,110,109,110,111,111,110,111,111,111,105,105,110,110,110,110,105,105,105,105,106,73,71,71,71,71,71,71,71,71,72,72,71,72,73,72,72,72,72,73,72,72,74,73,73,73,73,73,73,105,105,111,111,111,105,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,111,111,111,110,111,111,111,106,104,108,106,106,107,107,107,107,107,106,106,107,106,106,78,78,78,78,78,78,79,79,79,79,79,79,79,79,79,79,79,31,64,30,64,30,64,29,64,28,64,27,65,27,65,26,65,26,65,65,26,65,72,24,73,23,75,23,77,22,79,29,30,28,31,28,31,28,67,31,22,30,23,30,23,29,24,28,24,28,25,27,25,26,26,26,26,25,27,25,27,24,28,23,28,23,29,22,29,25,30,31,30,30,31,30,72,29,218,28,218,27,218,27,218,26,218,25,218,24,218,24,25,23,31,22,218,22,218,22,218,31,218,29,218,27,218,25,218,23,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,217,217,217,217,217,221,217,221,221,221,221,196,198,198,198,198,198,196,196,197,197,197,198,197,198,197,198,198,196,196,196,196,196,196,197,197,197,196,197,197,197,197,197,197,197,197,198,197,198,197,198,198,198,198,198,198,198,196,197,197,197,197,197,197,197,197,198,198,198,198,198,197,198,197,198,198,196,196,196,196,197,197,197,197,197,197 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,108,252,252,252,252,108,109,107,109,107,252,107,109,108,252,108,252,108,252,108,252,252,108,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,109,107,252,107,109,107,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,109,107,109,107,109,107,109,107,109,107,109,107,109,107,60,61,61,61,61,59,61,94,58,62,62,59,61,61,61,62,62,62,62,61,62,62,62,59,60,60,94,60,61,58,59,59,60,59,60,60,61,60,61,61,92,62,92,60,93,60,61,95,62,94,94,61,105,105,105,105,111,110,111,110,110,110,111,110,111,110,111,111,111,109,110,109,104,107,106,64,65,69,69,67,68,68,68,68,68,69,70,66,69,69,67,65,65,65,66,66,66,66,66,66,66,65,66,66,66,67,67,67,67,105,105,105,105,110,111,110,105,110,111,110,105,110,110,109,110,110,110,110,111,110,111,105,110,109,110,110,111,110,111,110,111,110,111,111,111,105,111,110,111,110,111,111,105,105,111,106,107,106,73,72,73,72,72,72,72,72,72,72,73,72,73,72,73,72,73,73,73,73,73,73,73,74,74,105,105,111,111,105,105,105,111,111,111,111,111,111,111,111,111,111,111,110,111,111,111,110,111,111,111,110,111,110,111,110,111,111,111,111,111,110,111,110,111,110,106,107,108,104,104,107,106,106,107,106,107,107,107,106,107,106,106,106,79,78,79,78,79,79,79,30,79,79,79,64,79,27,23,26,79,28,64,28,64,27,65,27,65,26,65,26,65,25,66,25,66,24,25,66,24,30,30,29,30,29,31,29,66,29,66,29,67,29,67,28,67,28,68,28,23,28,24,27,25,27,26,27,27,27,29,26,30,26,31,26,70,26,70,26,70,26,71,25,71,25,71,25,218,25,218,24,218,24,218,24,218,24,218,24,218,24,218,23,218,23,218,30,218,29,218,28,218,26,218,25,218,24,218,23,218,22,218,23,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,218,217,217,217,217,221,217,221,217,221,217,221,217,221,221,221,221,221,196,197,198,197,198,197,198,197,198,197,196,196,196,196,197,196,197,196,197,196,197,197,197,197,197,197,198,197,198,197,198,197,198,197,198,197,198,198,198,198,197,196,197,196,197,197,198,197,198,197,198,198,198,197,198,197,198,197,196,196,196,196,197,197,198,197,198,197,198 +,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,108,252,108,252,108,108,109,108,109,107,109,252,109,108,252,252,252,252,252,252,252,252,108,252,252,252,108,108,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,107,107,109,107,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,109,107,109,107,109,107,107,107,109,109,109,107,107,107,60,61,61,61,61,59,61,94,58,62,62,62,62,58,62,62,62,60,59,61,61,61,62,60,60,94,60,61,61,61,60,61,60,94,60,61,61,61,62,92,92,93,93,94,62,94,62,94,105,105,105,110,105,111,111,111,111,110,110,109,110,110,111,110,111,111,111,109,110,109,104,107,107,106,67,69,71,67,70,70,69,71,70,70,71,72,69,70,68,69,66,66,69,66,71,68,67,68,67,66,66,67,67,67,105,105,105,105,110,110,111,111,111,111,111,109,110,110,110,110,110,110,110,110,110,110,111,111,111,105,110,110,110,110,111,111,111,110,111,111,111,105,110,110,111,110,111,111,111,111,105,111,110,110,110,106,106,73,74,74,74,73,74,74,73,73,74,73,73,73,73,73,73,73,73,73,74,74,74,74,105,105,105,105,105,105,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,111,111,111,111,111,111,111,111,111,110,111,110,111,106,107,107,108,104,104,104,108,106,106,106,106,107,107,106,106,106,106,106,106,106,79,31,79,30,79,30,79,79,79,29,79,28,79,28,79,27,64,27,64,26,66,26,71,25,75,25,79,24,64,24,65,23,65,23,65,22,65,22,66,31,66,31,66,30,66,30,67,30,67,30,67,29,67,29,68,29,68,29,68,28,69,28,69,28,218,31,218,30,218,30,218,29,218,28,218,28,218,27,218,27,218,26,218,25,218,25,218,24,218,23,218,31,218,29,218,28,218,27,218,25,218,24,218,23,218,23,218,22,218,22,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,196,196,197,196,197,196,197,197,197,197,197,197,197,197,198,197,198,197,198,198,198,198,198,198,197,197,197,197,197,197,198,198,198,197,197,197,197,197,197,197,198,197,198,198,196,196,196,198,197,197,197,197,197,197,198,197 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,108,109,107,252,108,252,108,252,107,252,108,252,108,252,252,252,108,252,252,252,252,108,107,108,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,107,107,107,252,107,252,107,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,107,109,107,109,107,109,107,109,107,109,107,109,107,107,63,60,59,59,59,60,61,61,60,61,61,61,61,59,61,94,58,62,59,61,83,61,62,62,62,61,62,61,61,61,62,62,62,59,60,59,60,63,62,91,92,93,94,63,94,94,105,105,111,111,110,111,111,111,111,110,109,110,109,110,111,111,110,111,111,111,109,110,104,104,107,108,107,107,106,71,71,70,72,70,72,71,73,71,70,74,68,68,74,73,73,72,69,73,68,72,75,68,68,69,69,105,105,105,110,111,110,111,111,111,110,111,111,110,109,110,109,110,109,110,109,110,110,110,110,111,110,105,110,111,110,111,110,111,110,111,110,111,105,111,111,111,110,111,110,111,110,111,111,111,111,110,110,111,106,110,106,106,74,75,74,74,74,74,74,75,73,75,74,73,74,74,74,73,74,74,74,75,105,105,105,105,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,111,110,111,111,111,111,111,110,111,106,107,107,108,108,104,104,104,107,106,107,108,106,107,107,107,106,107,106,106,106,106,30,79,29,79,28,79,27,79,26,79,25,79,24,79,23,64,22,64,29,64,28,64,28,65,28,65,28,65,27,65,27,66,27,66,26,66,26,66,26,67,25,67,25,67,25,218,25,218,24,218,24,218,24,68,23,218,23,218,23,218,22,218,22,218,22,218,22,218,27,218,31,218,29,218,28,218,27,218,25,218,24,218,23,218,22,218,27,218,26,218,24,218,23,218,22,218,22,218,22,218,23,218,22,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,221,221,196,197,196,197,196,197,196,197,197,198,197,198,197,198,197,198,197,198,197,198,198,197,196,197,197,198,197,198,197,198,197,198,198,198,197,198,197,198,197,198,197,198,196,196,198,197,197,198,197,198,197,198,197,198 +,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,108,109,108,108,107,109,107,109,108,252,252,252,252,252,252,252,252,252,252,252,252,252,107,108,108,108,108,108,252,252,252,108,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,107,107,107,107,109,107,109,107,252,109,109,109,252,252,252,109,252,252,252,252,252,252,252,252,109,107,109,107,109,107,107,107,109,109,109,107,109,107,60,63,59,59,59,60,61,61,60,61,61,61,61,59,61,94,58,62,83,83,82,62,83,84,84,62,62,62,59,60,58,59,59,60,59,60,63,62,92,91,92,93,105,105,105,105,105,111,111,111,111,111,111,111,110,109,109,109,110,110,111,111,109,109,109,109,110,104,108,108,108,107,107,107,106,71,72,72,72,71,72,71,73,72,70,74,75,73,75,74,73,74,72,68,71,73,105,105,105,105,105,110,111,110,111,110,111,111,111,111,111,111,110,109,110,110,110,110,110,110,110,110,111,111,110,110,111,110,111,110,111,111,111,110,111,111,111,111,111,110,110,110,111,110,111,110,111,111,111,105,110,110,110,110,106,108,110,106,106,75,75,75,75,75,74,75,74,75,74,75,74,75,75,75,75,76,105,105,105,105,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,111,111,111,111,111,111,111,111,111,111,106,106,107,108,108,104,104,104,107,107,107,107,107,106,107,107,107,106,107,106,106,106,106,31,79,28,79,25,64,22,64,31,64,30,64,30,64,29,64,28,64,27,65,27,65,26,65,26,65,25,66,24,66,23,66,23,66,22,67,29,218,28,218,28,218,27,218,26,218,25,218,24,218,23,218,23,218,22,218,29,218,25,218,22,218,28,218,26,218,24,218,22,218,31,218,29,218,27,218,25,218,23,218,218,218,30,218,30,218,29,218,28,218,27,218,26,218,25,218,25,218,24,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,217,217,221,217,221,221,221,217,221,221,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,197,197,197,197,197,197,197,197,197,197,197,197,198,198,198,198,198,197,197,197,197,197,197,197,198,198,198,197,198,198,198,198,198,197,197,197,198,198,198,196,196,198,197,197,197,197,198,197,198,197,198,198 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,252,252,108,108,108,252,108,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,108,108,108,252,252,252,252,252,252,252,252,252,252,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,107,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,107,109,107,109,107,109,107,109,107,109,109,109,107,107,60,63,63,63,95,63,80,59,82,63,83,84,84,56,63,85,63,83,82,82,84,83,82,84,85,84,61,66,67,65,68,71,68,68,69,65,65,66,69,67,21,105,105,105,105,111,111,111,110,111,111,111,111,109,109,110,109,110,110,111,110,111,111,110,109,110,104,108,108,108,107,108,107,107,107,106,72,71,72,72,72,73,75,72,72,74,75,75,75,73,71,75,105,105,105,105,111,111,111,111,110,111,110,111,110,111,111,111,110,111,109,110,109,110,109,110,109,110,110,111,110,110,110,110,110,111,110,111,111,110,110,111,110,111,111,111,111,110,110,111,110,111,110,111,110,111,111,111,111,110,110,110,110,106,107,109,109,107,106,106,75,76,75,75,75,75,75,75,75,76,75,76,75,75,105,105,105,105,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,111,111,111,110,111,110,111,110,111,111,111,111,109,109,104,106,107,107,108,108,104,104,108,107,108,107,108,107,106,106,107,106,107,106,107,106,106,106,106,30,79,30,79,29,64,29,79,28,64,28,64,27,65,27,65,26,65,26,65,25,66,25,66,24,66,24,66,23,67,22,218,22,67,31,67,29,68,28,68,27,218,26,218,25,218,24,218,23,218,22,218,218,218,218,218,218,218,218,218,30,218,30,218,29,218,29,218,28,218,28,218,27,218,27,218,26,218,26,218,25,218,25,218,24,218,24,218,23,218,23,218,22,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,221,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,217,221,221,221,217,221,221,221,221,221,221,197,198,197,198,198,198,197,197,197,198,197,198,197,198,197,198,197,198,197,198,198,198,198,198,197,198,197,198,197,198,196,196,196,197,196,197,197,198,197,198,198,198,197,198 +,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,109,252,109,252,109,108,108,108,252,252,252,252,252,252,252,252,252,252,108,252,252,252,108,108,108,108,108,252,108,252,252,252,252,252,252,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,109,107,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,107,107,107,109,109,109,107,109,107,107,81,63,63,95,81,62,63,80,83,82,84,85,84,64,62,64,82,84,83,84,82,84,83,84,86,67,68,67,68,67,70,71,73,75,67,69,70,68,105,105,111,111,111,111,111,111,111,111,111,111,111,109,109,110,110,110,110,110,110,111,111,111,111,104,104,108,108,108,108,108,108,108,107,107,106,71,72,72,72,72,66,70,69,105,105,105,105,105,105,105,105,111,111,111,111,111,111,111,110,111,110,111,111,111,111,111,111,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,111,111,110,110,110,110,111,111,111,111,110,110,110,110,110,110,110,110,111,110,111,111,111,105,110,110,110,110,106,107,108,109,110,106,106,106,106,76,75,75,75,75,76,76,76,76,75,76,105,105,105,105,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,111,111,111,111,111,111,111,111,111,109,109,104,106,107,108,108,104,104,108,107,107,107,107,107,107,106,107,106,107,106,106,106,106,106,106,106,64,29,64,28,64,26,64,24,64,23,65,28,65,27,65,26,65,25,66,24,66,24,66,23,66,22,67,24,218,23,218,23,218,22,218,31,218,29,218,28,218,26,69,24,69,23,218,28,218,27,218,27,218,26,218,26,218,25,218,25,218,24,218,24,218,23,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,220,198,198,198,198,198,198,198,198,198,198,198,198,196,196,196,196,196,197,197,197,197,197,198,198,198,198,198,198 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,107,108,107,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,109,107,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,107,109,107,109,107,109,107,109,109,109,107,109,107,61,81,62,81,82,82,82,81,82,84,83,84,86,64,65,87,66,87,86,65,65,86,69,66,66,65,64,66,68,69,75,72,73,73,74,105,105,105,111,111,105,110,111,110,111,110,111,111,111,111,110,109,110,110,110,110,111,110,111,111,111,109,104,108,108,108,108,108,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,111,111,111,111,111,111,111,111,111,111,110,111,110,109,109,109,109,110,109,110,109,110,109,110,110,110,110,111,110,111,110,111,110,111,111,111,111,111,111,110,110,111,110,111,110,111,109,110,109,110,109,110,110,110,110,111,110,111,110,111,111,111,109,110,109,110,109,110,106,108,108,110,106,107,106,107,106,106,75,75,75,75,76,76,76,76,105,105,105,105,105,111,111,111,111,111,111,111,111,111,111,111,111,109,110,111,111,111,111,111,110,111,111,111,110,111,111,111,110,111,111,111,110,111,110,111,110,111,110,111,111,111,111,109,109,104,106,107,108,104,104,108,107,108,107,108,107,107,107,107,106,107,106,107,106,107,106,107,106,106,106,64,30,64,30,65,29,65,28,65,27,65,27,66,26,66,25,66,24,66,24,218,23,218,22,218,31,218,29,68,27,218,25,218,23,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,30,218,30,218,29,218,29,218,28,218,28,218,27,218,26,218,26,218,25,218,25,218,24,218,24,218,23,218,22,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,217,217,221,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,220,220,220,220,220,220,220,198,198,197,196,196,196,196,197,196,197,197,198,197,198,198,198,197,198,198,198 +,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,109,109,108,109,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,108,107,108,107,108,252,252,252,108,252,252,252,109,109,252,109,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,109,109,109,109,252,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,107,252,107,109,107,107,107,109,109,109,109,109,107,107,62,81,80,65,62,65,81,83,83,83,65,65,65,64,65,65,65,65,66,89,65,88,66,66,68,70,66,68,70,71,71,75,72,105,105,111,111,111,111,111,110,111,111,111,111,111,111,111,109,110,110,110,110,111,111,111,111,111,110,111,111,104,104,105,105,105,105,105,110,111,111,111,110,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,110,109,110,109,109,109,109,109,109,109,109,109,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,111,111,111,109,109,110,111,109,110,110,110,109,109,109,109,109,110,110,110,110,110,110,111,110,111,111,111,109,110,110,110,110,110,110,106,107,106,110,107,107,107,106,106,106,75,75,75,75,75,76,105,105,105,105,105,111,111,111,111,111,111,111,111,111,111,111,111,111,111,109,110,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,111,111,111,111,111,111,111,111,111,111,109,109,109,104,106,108,104,108,108,108,108,108,108,107,108,107,107,107,106,106,106,106,107,107,107,106,106,106,106,31,65,30,65,29,65,29,65,28,66,27,66,26,66,26,66,25,67,24,67,23,218,23,218,22,68,31,218,30,68,29,68,29,69,28,69,27,218,27,218,26,218,26,218,25,218,25,218,24,218,23,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,218,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,221,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,221,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,196,196,196,197,198,196,197,196,197,197,198,198,198,198,198,198,197,198 +,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,109,109,109,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,107,108,107,252,252,252,252,252,252,252,252,252,109,109,109,108,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,107,107,109,107,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,107,252,107,109,107,107,107,109,107,109,107,109,107,95,81,81,66,81,67,82,82,65,65,65,68,65,66,66,66,67,66,66,66,66,66,66,66,67,67,67,67,68,70,105,105,105,111,111,111,105,110,111,110,111,110,111,110,111,111,111,111,110,110,111,110,111,109,110,110,111,110,111,111,110,110,111,110,111,110,111,110,111,110,111,110,111,111,111,110,111,111,111,111,111,111,111,111,111,111,110,110,110,109,110,109,109,109,111,111,110,109,110,109,110,110,110,109,110,110,111,110,111,110,111,110,111,111,111,111,111,110,111,109,109,109,111,111,110,109,110,109,110,109,110,109,110,109,110,110,110,110,111,110,111,111,110,109,110,110,110,109,110,110,111,110,106,110,108,107,107,107,107,106,107,106,74,76,76,105,105,105,105,105,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,109,110,110,111,111,111,110,111,111,111,110,111,111,111,110,111,111,111,111,111,110,111,110,111,111,111,110,111,111,109,109,109,109,104,106,104,108,108,108,108,108,108,107,106,107,108,107,107,106,106,106,107,106,107,107,107,106,107,106,106,31,66,29,66,27,66,25,66,23,67,22,67,30,67,28,218,27,68,25,68,23,68,22,68,29,68,26,218,23,218,28,218,27,218,26,218,30,218,29,218,29,218,28,218,27,218,26,218,25,218,24,218,24,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,218,217,217,217,218,217,217,217,217,221,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,220,220,220,220,220,220,220,220,220,220,220,220,220,196,196,196,197,197,198,196,197,197,197,197,198,197,198,197,198,197,198,198,198 +,108,252,108,252,252,252,108,252,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,109,108,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,108,107,108,108,108,252,108,252,252,252,252,252,109,109,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,107,109,109,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,107,252,107,109,107,107,107,109,107,109,109,109,107,109,107,80,68,66,81,66,65,64,66,66,66,69,67,67,67,67,70,69,68,68,68,68,67,69,67,68,69,68,105,105,105,111,105,105,105,111,110,111,111,111,111,111,111,111,110,110,110,111,110,111,111,110,110,110,109,110,110,111,111,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,111,111,111,111,111,111,111,111,110,110,110,109,109,109,109,109,110,110,110,110,111,111,110,109,109,111,110,110,110,110,110,110,111,110,111,111,111,111,111,110,111,109,109,109,110,109,109,110,111,110,110,110,110,110,109,109,109,109,110,110,111,111,111,109,110,109,110,110,110,110,109,110,110,110,110,110,111,106,110,107,107,107,107,107,107,106,106,106,105,105,105,105,105,105,111,111,111,111,111,111,111,111,111,111,111,111,111,111,109,109,110,110,111,110,111,110,111,111,111,111,111,111,111,111,111,111,111,110,111,111,111,111,111,111,111,111,111,111,109,109,109,104,104,106,104,108,108,108,107,108,108,108,106,107,107,108,107,107,106,106,107,107,106,107,107,106,106,106,106,106,106,28,66,28,66,27,66,26,67,25,67,25,67,24,67,24,67,23,218,22,218,28,218,28,218,27,218,26,218,25,218,25,218,31,218,29,218,28,218,26,218,25,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,221,220,221,220,221,220,221,220,221,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,196,196,196,197,198,198,198,196,197,197,197,197,197,197,198,198,198,197,198,198,198,197 +,252,108,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,108,252,109,108,109,108,109,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,107,108,108,108,252,252,252,252,109,252,252,252,109,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,107,109,109,107,109,107,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,107,252,107,109,107,109,107,109,107,109,107,109,107,107,66,67,66,68,64,67,66,66,67,69,69,67,69,69,69,69,69,70,69,69,68,69,68,69,70,105,105,105,105,105,105,111,110,110,110,110,111,111,111,111,110,111,111,111,110,111,110,111,111,110,109,110,109,110,109,111,109,110,110,110,110,110,110,111,110,111,110,111,110,109,111,111,110,111,110,111,111,111,111,111,110,110,110,110,109,109,109,109,109,110,109,110,110,109,109,111,111,110,109,110,110,110,110,111,110,111,110,111,110,111,111,111,111,110,109,110,109,110,109,110,109,110,109,110,109,110,110,111,110,109,109,110,111,109,109,110,109,110,109,110,109,109,109,111,111,111,110,111,110,111,110,111,110,111,107,108,107,107,106,105,105,105,111,111,111,105,105,111,111,111,110,111,111,111,111,111,111,111,110,111,109,110,109,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,111,111,110,111,110,109,110,111,110,111,111,111,111,109,109,109,104,106,107,104,104,108,108,108,108,108,107,106,106,107,107,108,107,108,106,107,106,107,107,107,107,107,106,107,106,106,106,106,27,67,26,67,106,67,23,67,22,68,67,68,67,68,30,68,29,69,29,218,28,218,27,218,26,218,25,218,25,218,24,218,30,218,28,218,27,218,25,218,24,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,196,196,197,197,198,197,198,198,197,196,197,196,197,197,196,197,198,198,198,198,198,198,198 +,108,252,108,252,252,252,252,252,108,109,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,108,109,108,108,109,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,252,252,252,108,252,252,252,109,109,108,109,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,109,109,109,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,107,252,107,252,107,107,107,109,109,109,109,109,107,109,107,68,70,68,69,69,67,69,68,70,70,69,69,68,70,70,70,70,69,68,70,69,71,105,105,105,105,105,105,111,111,110,110,111,111,110,110,111,111,111,110,110,110,110,110,111,111,111,111,111,111,110,109,110,110,110,110,110,110,110,110,110,110,110,110,110,109,109,110,110,111,111,110,111,111,111,111,111,111,111,110,110,110,110,109,109,109,109,109,110,110,109,109,111,111,111,111,111,111,110,110,110,110,110,110,111,110,111,110,111,111,111,111,110,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,111,111,111,109,109,109,109,109,110,110,110,109,110,110,111,111,110,110,110,110,111,111,111,111,111,109,109,109,105,105,105,111,111,111,111,111,105,105,111,111,111,111,111,111,111,111,111,111,111,111,109,109,110,110,110,110,111,110,111,110,111,111,111,111,111,111,111,111,111,111,111,111,111,109,109,110,110,111,111,111,111,111,109,109,109,109,104,106,108,104,108,108,108,108,108,108,108,108,106,106,107,108,108,107,106,106,106,106,107,106,107,106,107,106,106,106,106,106,67,29,67,28,67,27,68,26,68,25,218,24,218,23,218,22,218,29,218,28,218,27,218,27,218,26,218,25,218,24,218,24,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,217,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,220,220,220,221,220,220,220,221,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,196,197,197,197,197,198,198,198,196,196,196,197,196,196,196,197,198,198,198,198,198,198,197 +,252,252,252,252,252,252,252,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,252,108,252,252,252,109,252,252,252,109,109,109,108,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,107,107,109,107,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,107,252,107,109,107,109,107,109,107,109,107,109,107,107,107,68,70,70,71,69,69,69,69,70,69,70,70,69,70,70,71,70,70,71,105,105,111,111,105,111,111,111,111,111,110,110,110,111,110,111,111,111,111,110,110,111,110,111,110,111,110,111,111,111,111,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,111,110,111,111,110,110,111,110,111,110,111,110,111,109,110,109,109,109,110,109,110,109,109,110,110,110,111,110,111,111,110,109,110,110,111,110,111,110,111,110,111,111,111,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,111,110,111,110,111,111,109,109,110,109,110,109,109,109,110,110,111,111,110,109,110,109,110,110,111,110,111,110,111,110,105,105,105,105,105,105,105,105,105,105,111,111,111,110,111,110,111,111,111,110,111,109,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,109,109,110,109,110,110,111,110,111,109,110,109,110,110,111,104,104,106,104,108,108,108,108,108,108,107,108,106,107,107,108,108,108,106,107,106,107,107,107,107,107,106,107,106,106,106,106,106,68,30,68,29,68,28,68,26,68,25,218,23,69,22,69,68,69,69,70,69,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,196,197,196,197,197,198,197,198,197,198,197,198,196,197,196,197,196,198,197,198,198,198,197,198 +,108,252,108,252,108,252,252,252,108,109,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,109,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,252,108,252,252,252,252,252,252,109,108,109,108,109,252,109,252,252,252,252,252,252,252,252,252,252,107,107,109,109,107,107,109,109,109,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,107,252,107,107,107,109,107,109,107,109,107,109,107,109,70,71,70,71,70,70,71,70,71,71,72,71,71,71,71,70,105,105,105,105,105,105,111,111,111,111,111,110,110,110,110,110,110,111,111,111,111,111,111,110,110,111,111,111,111,111,111,109,109,109,109,110,109,110,109,109,109,110,109,110,110,110,110,110,110,111,111,111,111,111,110,110,109,109,109,109,109,110,109,110,109,110,109,109,109,110,110,110,110,111,111,111,110,111,110,109,109,109,109,110,110,110,110,110,110,111,111,111,109,110,109,109,109,109,109,110,110,110,109,110,110,110,110,110,109,109,109,109,109,109,109,109,109,110,109,110,109,110,110,111,111,110,110,110,110,110,110,110,110,111,110,111,105,105,105,105,111,111,111,111,111,111,111,105,111,111,111,111,111,111,111,111,111,111,109,109,109,110,110,111,111,111,110,111,110,111,110,111,111,111,111,111,111,111,111,111,111,109,109,110,109,110,110,110,110,111,111,110,110,110,110,110,104,106,104,106,108,108,108,108,108,108,108,108,107,108,106,107,108,108,107,107,106,107,106,107,106,108,107,107,106,106,106,106,106,106,106,68,29,68,28,68,27,69,26,69,25,218,24,218,23,218,22,218,27,218,27,70,26,218,25,218,24,218,23,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,197,198,198,198,197,198,197,198,196,196,196,197,197,197,197,198,197,198,198,198,197 +,252,108,252,252,252,252,252,252,252,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,109,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,252,252,252,252,252,252,252,252,109,109,108,109,252,109,252,109,252,109,252,252,252,252,252,252,252,107,109,107,109,107,252,107,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,107,252,107,109,107,109,107,109,107,109,107,109,107,107,107,109,71,71,71,71,71,71,71,70,71,71,72,71,70,105,105,111,105,105,111,111,111,111,111,111,111,111,110,111,110,111,110,111,110,111,111,111,111,111,110,111,110,111,111,111,111,111,109,109,109,110,109,109,109,110,109,110,109,110,110,110,110,109,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,109,109,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,109,110,109,110,109,110,109,110,109,109,109,110,109,110,109,110,109,109,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,111,111,110,110,110,110,110,110,111,110,111,110,105,105,105,111,111,111,111,111,111,111,111,111,105,111,111,111,111,110,111,110,111,111,110,109,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,109,109,110,109,110,110,111,110,111,111,110,109,110,110,111,104,106,104,108,108,108,108,108,108,108,108,108,108,108,108,108,106,108,107,108,107,108,106,107,106,108,108,107,106,107,106,107,106,106,106,106,27,69,26,69,24,218,23,218,218,70,69,70,30,218,30,218,29,218,29,218,28,218,27,218,27,218,26,218,25,218,25,218,24,218,24,218,23,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,198,197,198,197,196,196,197,196,197,196,197,197,198,197,198,198,197 +,108,252,108,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,252,252,252,108,252,252,252,252,252,108,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,107,107,109,109,109,107,109,107,252,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,107,252,107,107,107,109,107,109,107,109,107,109,107,109,109,70,70,70,70,71,71,72,71,71,72,72,105,105,105,105,105,111,111,111,111,111,111,110,110,110,110,111,110,111,110,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,110,110,109,109,109,109,109,109,110,110,110,109,109,109,109,109,109,109,109,109,110,109,110,109,110,110,110,110,110,110,110,109,110,110,110,110,111,111,111,110,111,110,111,110,111,111,111,110,111,111,111,109,109,109,109,109,110,110,110,110,110,110,110,110,111,109,109,109,110,110,110,109,109,109,110,110,110,110,111,111,110,110,110,109,110,110,110,110,109,110,111,110,110,110,110,110,110,110,110,110,111,105,105,111,105,111,111,111,111,111,111,111,111,105,111,105,111,111,110,110,111,111,111,111,110,109,109,109,110,110,111,111,111,110,110,110,111,111,111,110,111,111,111,111,111,111,111,109,111,109,109,109,110,110,110,110,111,111,110,110,110,110,110,110,111,104,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,107,108,107,107,106,106,107,108,107,107,107,106,106,106,106,106,106,106,69,69,30,218,28,218,26,218,29,218,28,218,26,218,25,218,24,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,218,218,217,218,217,217,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,221,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,221,221,221,220,221,220,220,220,221,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,196,196,197,197,197,197,198,197,198,198,198,198 +,252,108,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,252,108,252,108,252,108,252,109,252,109,252,252,252,252,252,252,252,252,108,108,252,108,252,252,252,252,252,252,252,252,108,252,108,109,109,109,252,109,252,109,252,109,252,252,252,252,252,107,109,107,109,109,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,107,252,107,109,107,109,107,109,107,109,107,109,107,107,107,109,107,70,70,70,70,70,71,71,105,105,105,105,111,111,111,111,111,111,111,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,111,111,111,111,110,111,111,110,110,109,109,109,109,110,109,110,109,110,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,111,110,111,111,111,110,111,110,111,110,111,110,111,111,111,109,109,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,109,109,111,111,110,110,110,110,111,110,111,111,110,109,110,109,110,109,110,109,110,110,110,109,110,110,111,110,110,110,111,110,105,105,111,111,105,111,111,111,111,111,111,111,111,111,111,105,111,110,111,110,111,111,111,111,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,110,111,111,109,109,110,109,110,110,111,111,110,109,110,110,111,110,111,104,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,107,108,107,108,107,108,106,106,107,108,106,107,106,107,106,107,106,106,106,106,69,218,69,70,69,70,70,70,23,70,31,71,30,218,29,218,28,218,27,218,26,218,26,218,25,218,24,218,23,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,218,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,218,217,217,217,217,217,217,217,217,221,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,221,217,221,221,220,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,198,197,198,197,198,197,198 +,108,252,108,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,109,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,109,108,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,108,108,108,252,108,252,252,252,252,252,252,252,108,109,109,109,109,109,252,109,252,252,252,252,252,252,252,252,107,107,109,109,109,107,109,109,109,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,107,252,107,107,107,109,107,109,107,109,107,109,107,109,109,107,107,70,71,70,71,105,105,111,111,111,111,111,111,111,111,111,111,110,110,110,110,110,110,111,110,111,110,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,110,109,109,109,109,110,109,110,110,110,109,109,109,109,109,109,109,109,109,110,109,109,110,110,111,110,110,110,109,109,109,110,110,110,110,111,111,111,110,111,110,111,110,111,111,111,111,111,111,111,111,109,109,109,109,110,109,110,110,110,110,110,110,110,110,111,110,111,111,111,111,110,110,110,110,111,110,111,111,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,105,105,105,105,105,105,111,111,111,111,111,111,111,111,111,105,111,105,111,110,110,111,111,111,110,110,110,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,111,111,111,111,111,111,111,111,109,109,109,109,109,110,109,110,110,110,110,110,110,110,110,110,109,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,107,108,108,108,108,107,108,107,107,106,106,108,107,107,107,106,106,106,106,106,106,106,218,28,70,27,70,26,70,25,71,25,71,24,218,24,218,23,218,23,218,22,218,30,218,28,218,26,218,24,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,221,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220 +,252,108,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,108,108,109,108,252,108,252,108,252,109,252,109,252,252,252,252,252,252,252,252,252,108,108,108,252,252,252,252,252,252,252,252,252,252,108,109,252,109,252,109,252,109,252,252,252,252,252,252,252,107,109,107,109,107,109,107,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,107,252,107,252,107,109,107,109,107,109,107,109,107,107,107,109,109,107,107,105,105,105,105,111,111,111,111,111,111,111,111,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,110,110,110,110,110,110,109,109,110,109,110,109,110,109,110,109,109,109,110,109,110,109,110,109,110,109,110,109,110,110,111,110,111,110,109,109,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,109,110,109,110,110,111,111,110,109,110,109,110,109,110,109,110,110,111,111,111,111,111,110,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,110,110,105,105,105,111,111,111,105,111,111,111,111,111,111,111,111,111,105,111,105,111,110,110,109,109,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,109,109,109,109,110,109,110,109,110,109,110,109,110,110,110,110,111,110,109,108,108,108,108,108,108,108,108,108,108,105,105,105,105,111,105,104,104,104,104,104,104,104,108,107,108,106,108,106,107,106,107,106,107,106,107,106,106,106,70,29,218,29,218,28,218,27,218,26,218,26,218,25,218,24,218,23,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,221,221,220,221,220,221,220,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221 +,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,109,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,108,108,108,108,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,108,108,252,108,252,108,252,252,252,252,252,252,109,108,109,252,109,252,109,252,252,252,252,252,252,252,252,107,107,107,107,109,109,109,109,109,109,109,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,252,107,252,107,109,107,109,107,109,107,109,107,109,107,109,109,109,107,107,111,111,111,111,111,111,111,111,111,111,111,110,110,110,110,110,110,110,110,111,110,110,110,111,111,111,111,111,111,111,111,111,111,111,110,109,110,111,109,109,109,110,109,109,109,109,109,110,109,110,109,110,110,110,110,109,109,109,109,110,109,110,110,110,110,110,110,110,110,111,110,111,111,111,111,110,110,110,110,111,110,111,110,111,111,111,110,109,109,109,109,110,110,110,110,110,110,111,110,111,111,111,110,110,111,111,111,111,111,110,109,109,109,109,109,109,109,109,109,110,109,110,109,110,110,110,109,110,110,110,110,110,110,110,110,110,105,105,105,105,111,111,105,105,111,111,111,111,111,111,111,111,111,111,111,105,111,111,111,109,109,110,110,111,110,110,110,110,110,110,110,111,110,110,110,111,110,111,110,111,111,111,110,111,111,111,111,109,111,109,109,109,109,109,109,110,109,110,109,110,110,110,110,110,110,105,109,105,105,105,105,105,105,105,105,105,105,109,109,109,109,109,109,104,104,104,104,104,104,104,104,108,107,107,106,108,107,107,106,107,106,106,106,106,106,106,106,218,24,218,23,218,23,218,22,218,25,218,24,218,23,218,31,218,30,218,29,218,28,218,27,218,27,218,26,218,25,218,24,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,217,218,218,218,217,218,217,218,217,218,217,217,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,217,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220,221,220,220,220 +,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,108,252,108,109,108,252,108,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,108,108,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,109,252,109,252,252,252,252,252,107,109,107,109,109,252,107,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,107,252,107,252,107,109,107,109,107,109,107,109,107,107,107,109,109,107,107,107,111,111,111,111,111,111,111,111,111,111,111,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,111,111,110,111,111,110,109,110,110,109,109,110,110,111,110,109,109,110,109,110,109,110,109,110,110,111,110,109,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,111,111,111,110,110,111,110,111,110,111,110,111,110,111,110,109,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,111,111,111,110,109,109,109,109,109,109,109,109,109,110,109,110,109,110,109,110,109,110,109,110,110,110,109,110,110,110,105,105,105,111,105,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,105,111,110,111,110,109,109,110,110,111,110,111,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,110,111,109,110,111,109,109,110,109,110,109,110,109,110,110,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,111,110,109,110,110,111,110,111,111,111,109,104,106,107,108,104,104,108,107,107,106,107,106,107,106,107,106,107,106,107,106,106,24,218,23,218,23,218,22,218,25,218,31,218,29,218,27,218,26,218,24,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,218,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,218,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,217,221,221,221,221,221,221,221,221,221,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221 +,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,109,108,109,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,108,108,108,108,108,109,109,109,109,252,109,252,252,252,252,252,252,252,252,252,252,252,108,108,252,108,252,252,252,252,252,252,109,108,109,109,109,252,252,252,252,252,252,252,252,252,252,107,107,107,107,109,109,109,109,109,109,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,107,252,107,109,107,109,107,109,109,109,107,109,107,109,109,107,107,107,107,111,111,111,111,111,111,111,110,111,111,110,109,110,110,110,110,111,111,111,111,111,111,111,111,111,111,109,109,110,109,110,110,110,110,111,109,109,109,110,110,109,109,109,109,110,109,110,110,110,110,110,110,111,109,109,109,110,109,110,109,110,110,110,110,110,110,111,110,111,111,111,111,110,110,110,110,110,110,111,110,111,111,111,109,109,109,110,109,110,110,110,110,110,110,111,111,111,111,111,111,111,110,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,110,109,110,109,110,109,110,110,110,110,110,110,105,105,105,111,105,105,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,109,110,110,110,110,111,110,110,110,110,109,110,111,111,110,110,110,111,110,111,110,111,111,109,111,111,111,111,111,111,109,110,110,111,109,109,109,111,109,110,109,110,110,110,110,110,110,110,110,110,110,111,110,111,111,111,111,111,111,111,109,110,109,110,109,110,110,110,110,110,110,104,106,107,108,104,104,107,107,107,107,107,107,107,106,107,106,106,106,106,106,106,71,72,71,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220 +,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,108,108,109,108,252,108,252,108,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,108,109,108,109,252,109,252,109,252,252,252,252,252,252,252,107,107,107,109,107,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,107,252,107,109,107,107,107,109,107,109,107,107,107,109,107,107,107,107,107,111,111,111,111,111,110,111,110,111,110,111,111,110,110,110,110,111,110,111,111,111,110,111,111,109,109,110,110,111,111,110,109,110,110,109,109,110,109,110,109,110,109,110,109,110,109,110,110,111,110,111,110,109,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,111,111,110,111,110,111,110,111,110,111,110,111,110,109,109,110,109,110,110,111,110,111,110,111,111,110,110,111,110,111,111,109,109,109,109,110,109,109,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,105,105,105,111,111,105,110,111,111,111,105,111,111,105,105,111,105,111,111,111,109,111,111,111,105,111,110,109,109,110,110,111,111,111,110,111,109,110,109,111,110,111,110,111,110,111,110,111,110,109,110,111,110,111,110,111,111,109,109,110,109,111,110,111,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,111,111,109,110,109,110,109,110,109,110,110,110,110,111,110,104,106,107,107,104,104,104,107,107,107,107,106,107,106,107,106,107,106,106,106,106,29,218,28,218,26,218,25,218,24,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,221,217,221,221,221,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221 +,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,252,108,109,109,108,108,109,108,109,108,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,108,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,107,107,107,107,109,109,109,107,109,109,109,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,252,107,252,107,109,107,109,107,107,109,109,107,109,107,107,109,107,107,107,107,107,107,111,110,110,110,111,110,110,110,111,111,111,111,111,111,111,110,111,111,111,111,109,109,109,109,110,110,110,110,111,111,110,110,109,109,109,109,109,109,109,109,109,109,110,109,110,110,110,110,111,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,111,111,111,111,111,110,110,110,111,110,110,110,111,111,111,110,109,109,109,109,110,110,110,110,111,109,110,110,110,110,111,111,109,109,109,109,109,109,109,109,109,109,109,110,109,109,109,109,109,109,109,109,110,109,110,109,110,110,110,105,105,105,105,111,111,105,105,111,111,105,111,105,110,111,111,111,111,111,111,111,111,109,111,111,111,111,111,111,109,109,110,110,111,111,111,110,109,109,109,109,110,110,110,110,111,111,111,110,111,111,109,109,110,110,109,109,110,110,110,110,110,110,111,111,111,109,109,109,110,110,110,109,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,109,110,111,110,109,110,110,110,110,110,110,110,110,111,104,106,107,108,108,104,104,107,107,107,107,107,107,107,106,106,106,106,106,106,106,218,29,218,28,72,27,218,26,218,25,218,31,218,29,218,28,218,26,218,25,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,218,218,217,218,217,218,217,218,217,217,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,217,217,221,217,221,221,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,221,220,221,220,221,221,221,220,221,220,221,220,221,221,221,220,221,220,221,220,221,221,221,220,221,220,221,220,221,221,221,220,221,220,221,220,221,221,221,220,221,220,221,220,221,221,221,220,221,220,221,220,221,221,221,220,221,220,221,220,221,221,221,220,221,220,221,220,221,221,221,220,221,220,221,220,221,221,221,220,221,220,221,220,221,221,221,220,221,220,221,220,221,221,221,220,221,220,221,220,221,221,221,220,221,220,221,220,221,220,221,220 +,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,108,108,252,108,252,108,109,109,108,108,252,108,252,108,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,109,109,109,252,109,252,109,108,109,252,252,252,252,252,107,252,107,109,107,252,107,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,107,252,107,109,107,109,107,109,107,109,107,109,107,109,107,109,107,107,107,107,110,111,110,110,110,111,110,111,110,111,110,111,110,111,110,111,111,111,110,109,109,110,109,110,109,110,109,110,110,111,110,111,110,111,109,109,109,110,109,109,109,110,109,110,110,110,110,111,109,110,109,110,110,111,111,110,110,110,110,111,110,111,110,111,111,111,111,111,110,111,110,111,110,111,110,111,110,111,109,109,109,110,109,110,110,111,110,109,111,110,110,111,110,111,109,109,109,110,109,109,109,110,109,109,109,110,109,110,109,110,109,109,109,110,109,110,109,110,109,110,109,105,105,105,105,111,110,105,105,111,111,111,111,111,110,110,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,111,109,109,110,110,111,110,109,109,110,109,110,110,110,110,111,110,111,110,111,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,109,110,109,110,109,110,109,110,109,109,109,110,109,110,109,110,110,111,110,111,111,111,109,110,110,111,109,110,109,110,109,109,110,111,110,110,110,104,106,107,107,104,104,104,104,106,107,107,107,107,106,107,106,107,106,106,106,106,106,218,26,218,24,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,218,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,221,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,217,221,221,221,221,221,221,221,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221 +,109,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,252,109,109,108,108,108,109,108,109,108,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,109,109,109,252,252,252,252,252,252,252,252,252,252,252,107,107,107,109,109,109,109,109,109,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,107,252,107,109,107,109,107,109,107,109,107,109,107,107,109,109,109,109,107,107,107,111,109,109,110,110,110,110,110,110,110,111,110,111,111,111,111,111,111,111,109,109,109,110,110,110,110,110,110,111,111,111,111,111,109,109,109,109,109,110,109,109,109,110,110,110,110,109,109,110,110,110,110,110,110,111,111,110,110,110,110,111,110,111,111,111,111,111,110,110,110,110,110,111,110,111,110,111,109,109,109,110,110,110,110,111,111,109,111,110,110,111,111,109,109,109,109,109,109,109,109,109,109,110,109,109,109,109,109,109,109,109,109,109,109,109,109,110,109,105,105,105,105,105,111,105,105,105,111,111,111,111,111,111,110,110,110,110,110,110,110,111,110,111,111,111,111,111,111,111,105,111,111,111,109,110,110,111,110,109,109,109,109,110,110,110,110,110,110,110,110,111,111,111,111,110,110,110,110,110,110,110,110,111,111,111,111,111,109,109,109,109,109,110,109,109,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,109,110,110,111,110,110,110,104,106,107,108,104,104,104,106,108,106,107,107,107,107,107,107,106,107,106,106,106,106,106,218,25,218,24,218,31,218,30,218,28,218,27,218,26,218,24,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,217,221,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221 +,252,108,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,108,252,108,109,109,108,108,252,108,252,108,252,108,108,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,252,109,252,252,252,252,252,252,252,252,107,107,109,107,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,107,252,107,109,107,107,107,109,107,109,107,107,107,109,107,109,109,107,107,107,107,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,109,111,110,109,110,109,110,109,110,109,110,110,111,110,111,110,109,110,109,109,110,109,110,110,110,110,111,110,111,110,111,110,111,110,111,111,111,111,111,110,111,110,111,110,111,110,111,110,111,109,110,109,110,109,110,110,111,110,109,110,111,110,111,111,109,109,109,109,109,109,110,109,110,109,110,109,110,109,109,109,110,109,110,109,110,109,110,109,110,105,105,105,105,105,105,105,105,111,111,110,111,110,111,111,111,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,111,111,109,111,110,111,109,110,109,110,109,110,109,110,110,110,110,111,110,111,110,111,111,111,110,111,110,111,110,111,110,111,111,111,109,109,109,110,109,109,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,111,109,109,110,110,111,111,111,104,106,106,108,108,104,104,104,106,106,106,108,107,107,107,107,106,106,106,106,106,106,106,106,218,218,218,218,218,218,30,218,29,218,27,218,26,218,25,218,24,218,28,218,24,218,218,218,218,218,218,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221 +,252,252,109,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,109,109,109,108,108,108,108,108,252,108,108,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,109,109,109,252,252,252,252,252,252,252,252,252,107,107,107,109,109,109,109,109,109,109,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,252,107,252,107,109,107,109,109,109,107,109,107,109,107,107,107,109,109,109,107,107,107,107,110,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,110,111,109,110,110,111,111,109,109,110,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,109,109,109,109,110,110,110,110,110,110,111,110,111,111,111,110,111,111,111,109,111,111,111,111,111,111,110,109,109,109,109,109,110,110,110,110,110,110,109,109,109,110,111,111,110,109,109,109,109,109,109,109,109,109,109,109,110,109,109,109,110,110,110,109,109,109,109,109,109,109,105,105,105,105,105,105,105,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,110,110,110,110,111,111,111,110,111,111,111,111,111,111,111,111,111,110,110,110,110,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,111,111,111,111,110,110,110,110,111,111,111,111,111,111,109,109,109,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,109,109,110,110,110,111,111,111,110,104,106,107,108,104,104,104,107,107,106,106,106,107,107,107,107,107,107,106,106,107,106,106,106,106,27,218,27,218,26,218,25,218,25,218,24,218,23,218,22,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,217,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,217,217,221,217,221,221,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220 +,252,252,252,109,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,109,109,109,108,108,252,108,252,108,108,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,107,109,107,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,107,109,107,107,107,109,109,109,107,109,107,107,109,109,107,109,109,109,107,107,107,110,109,110,110,111,110,110,110,111,110,111,110,111,110,111,110,111,110,109,109,111,111,111,111,110,109,110,109,110,109,110,109,110,109,110,110,110,110,111,110,111,110,109,109,110,109,110,109,110,110,110,110,111,110,111,111,111,111,111,110,111,109,111,110,111,110,111,109,110,109,110,109,110,109,110,110,111,110,111,110,109,109,109,110,111,111,110,109,109,109,109,109,110,109,110,109,110,109,109,109,110,109,110,109,110,109,110,109,110,109,109,105,105,105,105,105,111,111,111,111,111,111,111,111,111,110,111,111,111,111,111,111,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,110,111,110,110,110,109,109,110,109,110,109,110,110,110,110,111,110,111,110,111,111,111,111,111,110,111,110,111,111,111,111,111,109,110,109,109,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,109,110,109,110,110,111,110,111,111,111,110,111,110,106,108,104,107,107,106,107,106,107,106,106,107,107,106,107,106,106,106,106,106,106,106,218,31,218,29,218,28,218,27,218,25,218,24,218,23,218,22,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,218,217,217,217,217,217,217,217,217,221,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,217,221,221,221,221,221,221,221,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221 +,108,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,109,108,109,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,109,108,109,108,109,108,109,108,109,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,109,252,109,252,252,252,252,252,252,252,252,252,252,252,107,109,109,109,107,109,109,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,107,109,107,109,107,107,109,109,107,109,107,107,107,109,107,109,109,109,109,107,107,107,110,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,109,110,111,111,111,111,111,110,109,110,110,110,110,110,110,110,110,110,110,111,110,111,111,111,111,111,109,111,111,110,110,110,110,110,110,111,111,111,111,111,110,111,111,111,111,111,111,110,110,110,109,109,109,109,109,110,109,110,110,110,110,110,109,109,109,109,110,111,111,111,109,109,109,109,109,109,109,110,109,110,109,109,109,109,109,110,109,110,109,110,110,109,109,105,105,105,105,105,111,111,111,111,111,111,105,111,111,111,110,111,111,111,111,111,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,111,111,111,111,111,110,110,110,110,110,110,109,109,109,109,109,110,110,110,110,110,110,110,110,111,111,111,111,111,110,111,110,111,111,111,111,111,109,109,109,109,109,110,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,109,109,109,110,110,110,110,111,111,110,110,110,110,111,110,106,107,107,106,107,106,106,106,106,107,106,108,107,107,107,106,107,107,106,106,106,106,218,218,218,31,218,30,218,29,218,28,218,27,218,26,218,24,218,23,218,22,218,218,218,218,218,218,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,109,109,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,108,109,252,109,108,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,109,252,109,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,107,109,107,107,107,109,107,109,107,109,107,107,109,109,107,109,109,109,107,107,107,110,110,110,110,109,110,111,110,111,110,111,110,111,110,111,110,111,109,110,109,111,111,109,109,110,110,111,110,111,111,111,110,111,110,111,110,111,110,111,109,110,110,111,109,110,110,111,110,111,110,111,111,111,110,111,110,111,110,111,111,111,111,110,109,109,109,110,109,110,109,110,109,110,110,110,110,111,110,111,109,109,111,110,110,111,110,111,111,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,105,105,105,105,105,111,111,111,111,111,111,111,111,111,111,111,111,111,110,111,110,111,111,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,110,111,110,111,109,109,109,109,109,110,109,110,110,111,110,111,110,110,110,111,110,111,110,111,110,111,110,111,111,111,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,110,109,109,110,110,111,110,110,110,111,110,111,110,111,104,111,109,108,107,107,106,107,106,106,106,106,107,106,108,107,106,106,106,107,106,107,106,106,106,218,25,218,23,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221,220,221 +,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,108,109,108,109,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,109,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,252,109,109,109,252,252,252,252,252,252,252,252,252,252,252,107,109,107,109,107,107,107,109,109,109,107,107,107,109,107,109,109,109,109,109,107,107,109,110,110,110,110,111,111,111,110,111,110,111,111,111,111,111,109,111,111,111,111,109,110,111,110,110,110,110,110,111,111,111,110,111,110,111,111,111,111,109,110,110,111,111,110,110,109,110,110,110,110,111,111,111,111,111,111,111,110,111,109,109,109,109,109,109,109,110,110,110,110,110,110,110,110,110,110,110,110,111,109,109,109,110,110,110,110,111,111,109,109,110,109,109,109,110,110,110,109,110,110,110,110,110,110,105,105,105,105,111,111,111,111,111,111,111,111,105,110,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,111,110,111,110,111,111,111,110,111,111,111,111,111,111,111,110,110,109,109,109,109,109,109,109,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,111,109,109,109,110,109,109,109,110,110,110,109,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,109,110,109,110,111,111,110,110,110,110,110,110,110,111,104,111,109,108,108,107,107,107,106,107,106,106,106,107,106,108,107,107,106,107,107,108,106,106,106,106,31,218,29,218,27,218,26,218,24,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,217,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,217,217,221,217,221,221,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221 +,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,108,109,252,109,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,109,107,109,107,109,107,109,107,109,107,109,107,107,107,109,107,109,109,109,107,109,107,110,109,110,110,111,110,111,110,111,111,111,110,111,109,111,109,111,110,111,111,110,109,110,110,111,110,111,111,111,110,111,110,111,111,111,110,111,110,109,109,111,111,111,111,111,110,111,110,111,110,109,109,110,110,111,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,110,109,109,110,109,110,110,111,111,111,109,110,109,110,109,110,109,110,109,110,109,110,109,110,105,105,105,105,111,111,110,111,111,111,111,105,111,105,110,111,111,111,110,111,111,111,110,111,111,111,111,111,111,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,109,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,111,111,111,111,109,110,109,110,109,110,109,110,109,110,109,110,110,110,109,110,110,111,110,110,110,111,110,111,110,109,109,110,109,110,110,111,110,111,111,111,110,111,110,110,110,111,110,111,104,111,109,108,107,108,107,107,106,107,106,107,106,106,106,108,106,107,106,106,106,107,107,107,106,107,106,106,30,218,28,218,26,218,31,218,28,218,25,218,23,218,217,218,218,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,217,221,221,221,221,221,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221,221,221,220,221 +,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,109,108,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,108,109,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,107,109,107,109,107,109,107,109,107,109,107,107,107,107,107,109,109,109,109,109,107,107,107,110,110,110,110,111,110,111,111,111,111,111,111,111,111,111,111,111,111,110,110,110,110,110,110,111,110,111,111,111,111,111,110,111,111,111,111,109,109,109,110,109,109,109,109,109,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,111,109,109,109,110,110,111,111,111,110,110,110,110,110,110,110,111,111,111,111,111,111,109,109,110,109,110,110,110,110,110,110,105,105,111,111,111,111,110,110,111,111,111,105,105,111,111,110,111,111,111,111,111,105,111,110,111,111,111,111,111,111,111,110,110,110,110,109,111,110,111,110,111,111,111,111,111,111,111,111,109,109,109,109,109,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,111,111,111,111,111,111,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,109,110,110,110,110,110,110,111,109,109,109,110,110,110,110,110,110,111,111,111,111,110,110,110,110,110,110,104,104,111,106,108,108,108,107,107,107,107,106,106,106,107,107,106,106,106,107,107,106,106,107,107,106,106,106,106,106,106,26,218,24,218,22,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,217,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221 +,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,252,109,108,109,252,109,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,109,107,109,107,109,107,109,107,109,107,109,107,109,107,109,107,109,107,109,109,109,107,107,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,111,110,109,110,109,110,110,110,110,111,110,111,110,111,110,111,111,111,110,109,109,110,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,109,110,109,110,109,110,110,111,110,111,111,110,110,110,110,111,110,111,110,111,110,111,110,111,111,111,111,110,109,110,105,105,105,105,105,105,110,111,110,111,110,111,105,111,110,111,110,111,111,111,111,111,111,111,110,111,110,111,110,111,111,111,109,110,109,111,110,111,110,111,110,111,110,111,110,111,111,111,111,109,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,111,110,111,110,111,109,111,110,111,110,111,111,111,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,109,111,110,111,110,111,110,111,109,110,109,110,109,110,110,111,110,111,110,111,111,111,110,111,110,111,110,104,106,108,104,109,108,108,107,108,107,107,106,107,106,107,106,107,107,106,107,106,107,106,106,107,107,106,106,107,106,106,106,218,25,218,31,218,28,218,25,218,22,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,217,221,217,217,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,217,221,221,221,221,221,221,220,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221 +,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,108,109,108,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,252,252,108,252,108,252,108,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,252,109,109,109,252,252,252,109,252,252,252,252,252,252,252,107,107,109,109,107,109,107,109,107,109,107,107,107,107,107,109,107,109,109,109,107,107,107,107,110,111,111,111,110,111,109,111,111,111,111,111,111,111,109,109,109,110,110,110,110,110,110,110,110,110,110,110,110,111,111,111,111,111,111,110,110,111,109,109,109,109,109,109,109,110,109,109,109,110,110,110,109,110,110,110,110,110,110,110,110,110,110,110,110,109,109,109,109,110,110,110,110,110,110,111,111,111,110,110,110,110,110,110,110,110,110,110,110,111,111,111,111,111,111,111,105,105,105,111,111,110,110,110,110,111,111,111,111,111,111,110,110,111,111,111,111,105,111,111,110,111,111,111,111,111,111,111,110,110,110,111,111,111,110,111,110,111,111,111,111,111,111,111,111,109,109,109,109,109,109,109,109,110,110,110,110,110,110,110,110,110,110,110,110,109,110,111,110,111,111,111,111,111,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,109,110,111,110,110,110,110,110,111,109,109,109,110,110,110,110,110,110,111,111,111,111,111,111,110,110,110,110,106,107,109,104,109,107,108,108,108,107,107,107,107,107,106,106,106,107,107,106,106,107,107,107,106,107,106,107,106,107,106,106,106,106,218,218,218,218,218,218,218,218,218,218,218,218,218,217,218,218,218,217,218,217,217,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,221,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,109,252,109,108,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,109,107,107,109,107,109,107,109,107,109,107,109,107,107,107,109,107,109,109,109,109,109,107,107,107,110,109,110,110,110,110,111,110,111,111,111,109,109,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,111,111,111,110,110,111,110,111,110,111,109,109,109,105,105,105,105,105,105,105,105,110,109,110,109,110,109,110,110,111,109,109,109,110,109,109,109,110,109,109,109,110,110,111,111,110,109,110,110,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,110,105,105,111,111,111,111,110,110,111,110,111,110,111,110,111,110,111,109,110,110,111,111,111,110,111,111,111,110,111,110,111,111,111,111,110,109,110,111,111,110,111,110,111,111,111,110,111,111,111,110,109,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,109,110,111,109,111,111,111,111,111,109,110,109,110,109,110,109,110,109,110,109,109,111,110,109,109,109,111,111,110,110,109,110,111,110,109,109,110,109,110,110,111,110,111,111,111,111,111,111,111,110,111,110,106,107,108,106,104,104,108,107,108,108,108,107,108,107,107,106,106,106,108,107,106,106,106,107,107,106,106,106,107,107,107,106,106,106,106,106,218,218,218,222,218,218,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221 +,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,108,109,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,252,109,108,252,108,252,108,252,108,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,107,109,109,109,109,252,109,252,109,252,252,252,252,252,252,252,109,109,107,109,109,109,107,109,107,109,107,109,107,107,107,107,107,109,109,109,109,109,107,107,107,107,107,110,110,110,110,110,110,111,111,111,111,111,111,110,110,110,109,109,109,110,110,110,110,111,111,109,109,110,110,110,110,110,110,110,110,111,110,111,105,105,105,105,109,107,107,106,106,106,106,106,105,105,105,105,105,105,105,105,105,105,109,109,109,109,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,111,105,105,111,111,111,111,110,110,110,110,110,111,110,111,111,111,110,111,111,110,110,110,110,105,111,111,110,110,110,111,110,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,110,110,110,110,110,109,109,109,109,109,109,109,110,109,110,110,110,109,110,110,110,110,110,110,109,110,110,109,110,110,111,111,111,109,109,109,110,109,110,109,110,110,110,110,109,110,111,109,110,110,111,111,109,111,110,110,111,110,111,110,109,109,110,110,111,111,111,111,111,111,111,111,111,110,110,110,106,107,108,104,104,104,106,104,108,107,108,108,108,107,107,107,108,107,107,106,107,106,106,106,107,107,107,106,107,107,107,106,107,106,106,106,106,218,218,218,218,218,218,218,218,218,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,221,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,108,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,252,109,252,109,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,107,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,109,107,109,107,109,107,109,107,109,107,109,107,109,107,107,107,109,107,109,107,109,109,109,107,107,107,107,109,110,110,111,110,111,110,111,110,111,110,111,110,111,111,110,110,111,110,111,110,109,109,110,109,109,109,110,110,111,110,111,110,105,105,105,105,109,109,110,105,105,111,104,107,106,106,106,106,106,106,106,106,107,107,107,107,107,105,105,105,105,108,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,110,110,111,110,105,105,111,111,111,110,110,110,111,110,111,110,111,110,111,110,111,105,111,110,111,110,111,110,111,111,111,110,111,110,111,110,111,110,111,111,111,110,111,111,111,111,110,109,110,110,110,110,110,110,110,110,110,109,109,109,110,109,110,109,110,109,110,109,109,109,110,110,111,110,111,110,111,109,109,109,110,110,111,110,111,111,110,109,110,109,110,109,110,109,110,109,110,109,111,109,110,110,111,109,111,110,111,110,111,110,111,110,111,110,111,109,111,110,111,110,111,111,111,110,111,110,111,110,106,107,104,104,110,110,104,106,107,107,108,108,104,104,108,107,108,107,107,106,106,106,107,106,106,106,108,107,107,106,107,107,106,106,107,106,107,106,106,104,104,104,104,104,218,218,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,218,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,222,222,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221 +,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,108,109,108,109,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,252,252,252,252,108,252,108,252,108,252,108,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,107,109,109,252,109,109,109,252,252,252,252,252,252,252,109,109,107,107,107,109,109,109,107,109,107,109,107,109,107,109,107,107,107,107,107,109,109,109,109,109,107,107,107,110,110,110,110,111,110,111,110,111,111,111,111,111,111,110,110,110,110,109,109,110,109,110,110,110,110,110,110,111,105,105,105,105,109,109,109,110,105,105,105,111,111,111,104,107,106,107,106,107,106,107,106,107,106,107,106,107,106,107,107,108,108,109,108,109,109,109,109,110,109,110,109,110,110,110,109,110,110,110,110,110,110,110,110,110,110,110,105,105,111,111,111,111,110,110,110,110,110,110,110,111,111,111,109,110,105,111,110,111,111,110,110,111,111,111,110,110,110,110,110,111,111,111,111,111,111,111,111,111,111,110,110,110,110,110,110,110,110,110,110,110,109,109,109,109,109,109,109,110,110,110,109,109,110,110,110,111,111,111,110,111,109,109,109,110,110,110,110,111,110,111,111,111,109,110,109,110,110,110,110,110,109,109,109,110,110,110,111,111,110,110,110,111,110,110,110,111,111,111,111,111,111,111,111,111,111,111,111,110,109,109,110,110,104,104,110,111,111,109,104,106,106,107,107,108,108,104,104,104,108,108,107,107,106,106,106,107,107,106,106,107,107,107,106,108,106,108,106,106,106,106,106,106,104,104,104,104,104,104,104,104,104,104,104,218,217,218,217,218,217,218,217,217,217,217,217,217,221,217,217,217,221,217,221,217,221,217,221,221,221,221,221,221,221,217,221,217,221,221,221,222,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,109,252,109,252,109,108,252,252,252,108,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,109,107,109,107,109,107,109,109,109,107,109,107,107,107,109,107,107,107,109,107,109,107,109,107,109,107,107,107,107,107,111,110,111,110,111,110,111,110,111,110,111,111,109,109,110,109,110,109,110,110,110,110,110,110,105,105,105,105,105,105,105,105,105,105,105,105,111,110,111,110,111,111,111,104,107,106,107,106,107,106,107,107,108,107,107,107,107,107,107,108,107,108,109,108,109,108,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,109,110,110,105,105,105,111,111,110,111,110,111,110,111,110,111,110,111,110,111,109,111,111,111,111,110,110,111,110,111,111,110,109,110,110,111,110,111,110,111,110,111,111,111,110,111,111,110,109,110,110,110,109,110,110,111,110,110,109,110,109,110,109,110,109,110,109,109,109,110,109,110,110,111,111,111,110,111,110,109,109,110,109,110,109,110,110,111,110,111,111,110,109,110,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,110,111,111,111,109,110,109,110,110,111,110,111,110,109,109,110,109,104,106,107,106,107,107,108,108,104,104,104,104,107,106,107,106,107,107,107,106,106,107,108,107,107,106,106,107,107,106,107,106,106,106,104,104,104,104,104,104,104,104,104,104,104,106,104,217,218,217,217,217,218,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,222,222,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221 +,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,109,109,109,252,109,252,252,252,252,252,252,109,109,107,107,109,107,109,109,109,107,109,107,107,109,109,107,109,107,107,107,109,107,109,109,109,109,109,107,107,107,107,110,110,110,111,110,111,110,111,111,111,109,109,109,109,109,110,109,110,110,110,105,105,105,105,111,111,111,111,111,110,110,110,110,110,110,110,110,111,111,111,111,111,111,104,107,107,106,107,107,107,106,107,107,108,107,107,107,107,107,107,108,108,108,109,108,109,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,105,105,105,105,105,105,105,111,111,110,110,110,110,109,110,110,111,111,111,111,105,111,111,110,111,111,111,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,111,111,111,110,110,110,110,110,110,110,110,110,110,110,109,109,109,109,109,109,110,109,109,109,110,110,110,110,111,111,111,110,111,110,109,109,110,110,110,110,110,110,111,111,111,109,110,109,110,110,110,110,110,109,109,109,110,110,111,111,111,110,110,110,111,110,111,110,111,111,111,111,111,111,111,111,111,111,111,109,109,109,110,110,111,111,111,109,110,110,110,110,104,106,106,106,107,107,108,108,108,108,104,104,104,104,104,106,106,106,107,107,107,106,106,107,107,107,107,106,108,106,107,106,106,106,106,106,104,104,104,104,104,104,104,104,104,106,107,108,104,217,218,217,218,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,217,221,222,221,217,221,217,221,222,221,222,221,222,221,222,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,107,109,252,109,252,109,252,109,252,252,109,109,107,107,109,107,109,107,109,109,109,107,107,109,109,107,109,107,107,107,109,107,109,107,109,109,109,107,109,107,107,107,107,110,111,110,111,110,111,110,111,109,109,109,110,109,110,109,105,105,105,105,111,105,105,111,111,111,111,109,110,109,110,110,110,110,111,110,111,110,111,110,111,111,110,104,107,107,107,106,107,107,107,107,107,107,108,107,107,107,107,107,107,108,107,108,109,108,110,108,110,109,110,109,110,109,110,109,110,109,110,109,110,105,105,105,105,105,111,111,111,110,109,109,110,109,110,110,111,110,111,110,111,111,105,111,110,110,111,111,110,109,110,109,110,110,111,110,111,110,111,110,111,110,111,111,111,111,111,111,110,110,110,110,110,110,110,110,110,110,111,109,109,109,110,109,110,109,110,109,110,109,110,110,110,110,111,110,111,110,111,109,110,109,110,110,111,110,111,109,110,109,110,109,110,109,110,109,110,110,109,109,111,111,111,110,111,110,111,110,111,110,111,110,111,110,111,109,110,109,110,109,110,110,111,110,111,111,110,110,111,111,110,109,110,110,110,110,104,106,107,106,107,107,108,107,108,108,104,108,104,104,104,104,107,106,107,106,107,107,106,106,106,106,108,107,106,108,107,106,107,106,107,106,106,106,104,104,104,104,104,106,104,106,107,107,104,104,106,217,218,217,217,217,217,217,217,217,217,217,217,217,217,221,217,221,217,221,217,221,221,221,221,221,217,221,221,221,221,221,221,221,221,221,221,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222 +,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,108,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,252,109,252,252,108,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,107,107,107,252,109,252,109,252,252,252,252,252,109,107,107,107,107,107,107,109,109,109,109,107,109,109,107,109,107,109,107,107,107,107,107,109,109,109,107,109,107,107,107,107,107,110,110,110,110,110,110,111,109,109,109,105,105,105,105,105,105,105,111,105,105,111,111,111,110,110,110,110,110,110,110,110,110,110,110,111,111,111,111,111,111,111,104,108,107,107,107,108,107,107,107,107,107,107,107,107,108,107,108,107,108,107,108,107,108,109,108,110,109,109,109,110,109,110,109,110,110,110,109,105,105,111,111,111,111,111,111,111,110,110,110,109,109,110,110,111,111,111,111,111,111,105,111,111,110,111,110,111,109,110,109,110,110,110,110,110,110,110,110,111,111,111,111,111,111,111,111,111,110,110,110,110,110,110,110,110,110,110,109,109,109,109,109,110,111,110,109,110,110,110,110,110,110,110,110,111,110,111,110,109,110,111,111,111,109,109,109,110,109,110,109,110,110,110,109,110,110,110,109,111,110,110,110,110,110,110,110,111,110,110,110,111,111,111,109,109,109,110,110,110,110,110,110,111,111,109,111,110,110,110,110,110,110,110,110,110,110,104,106,107,107,107,107,108,108,108,108,104,104,104,104,108,107,106,106,107,107,107,106,106,106,106,108,107,106,108,106,107,107,106,106,107,106,106,106,104,104,104,106,104,104,104,106,107,108,104,106,106,217,218,217,217,217,217,217,217,221,217,221,217,221,217,221,217,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,221,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,108,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,252,107,252,109,252,109,252,109,252,109,252,252,109,107,107,107,109,107,109,107,109,107,107,107,109,107,109,107,109,107,107,107,109,107,109,107,109,109,109,107,109,107,107,107,109,107,110,110,111,110,111,105,111,105,105,110,105,110,105,111,111,110,111,111,111,111,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,111,104,104,108,107,108,107,107,107,107,107,107,107,107,107,107,107,107,108,107,108,107,108,108,108,108,108,109,108,110,108,110,109,110,109,110,109,110,105,105,111,111,110,111,110,111,110,111,110,111,110,111,109,110,109,110,110,111,111,111,105,111,110,111,110,111,110,111,109,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,111,111,110,111,110,110,109,110,110,110,110,110,110,111,109,110,109,110,110,111,111,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,111,111,111,111,109,110,109,110,109,110,109,110,109,110,109,110,110,110,109,110,110,111,110,110,110,111,110,111,110,111,110,111,110,111,109,110,109,110,109,110,110,111,110,111,111,111,110,111,111,110,109,110,110,110,109,110,110,111,110,104,104,106,106,107,107,108,108,104,104,104,104,106,108,107,106,106,106,107,106,107,106,106,106,106,107,106,107,107,106,107,106,106,106,107,106,106,104,104,104,104,104,104,104,106,107,104,106,106,106,218,217,218,217,218,217,217,217,217,217,217,217,217,217,222,221,217,221,217,221,221,221,222,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,108,252,108,252,252,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,107,107,107,252,109,252,252,252,252,252,252,109,107,107,107,107,107,109,109,109,109,107,107,109,109,109,107,109,107,109,107,107,107,109,107,109,109,109,107,109,107,107,107,107,107,107,107,105,111,111,105,111,111,111,111,111,111,111,111,111,111,111,110,110,110,110,110,110,110,110,110,110,110,111,110,111,111,111,111,111,111,111,111,104,108,108,108,108,107,108,107,108,108,108,107,107,107,107,107,107,108,107,107,107,108,107,108,107,108,108,108,109,108,109,109,110,109,110,109,105,105,111,111,111,111,111,110,110,110,110,110,110,110,110,110,111,110,109,110,110,111,111,111,110,110,111,110,111,111,111,109,109,109,110,110,110,110,110,110,110,110,111,110,111,111,111,111,111,111,111,111,110,110,110,110,110,110,110,110,109,109,110,110,110,110,111,111,111,109,110,110,110,110,110,110,111,110,111,111,111,111,111,111,111,111,111,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,110,111,111,109,110,110,111,109,109,109,109,110,110,110,110,110,110,111,111,111,111,110,110,110,110,110,110,110,104,106,106,107,107,108,108,104,104,104,104,107,107,107,108,106,106,106,107,107,107,106,106,106,107,107,107,106,108,107,107,107,106,106,107,107,107,106,104,104,104,104,104,106,107,104,106,107,106,106,106,218,217,217,217,217,217,217,221,217,221,221,221,217,217,217,221,222,221,217,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,221,221,221,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221,221,221,222,221,221,221,221,221 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,107,107,252,107,252,109,252,109,252,252,109,109,107,107,109,107,109,107,109,107,109,107,109,107,109,107,109,107,109,107,107,107,109,107,109,107,109,109,109,107,109,107,107,107,107,107,107,107,111,110,111,110,111,111,111,110,111,111,111,109,110,109,110,109,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,104,108,108,108,108,107,108,107,108,108,108,108,108,107,108,107,107,107,107,107,107,108,107,108,107,108,108,108,107,108,109,108,110,109,110,105,105,105,105,111,110,109,110,109,110,109,110,110,110,110,111,110,111,110,111,110,109,111,111,111,111,110,111,110,111,110,111,111,110,109,110,109,110,110,110,110,111,110,111,110,111,110,111,111,111,110,111,111,111,110,110,110,110,110,110,110,109,109,110,109,110,110,111,110,111,109,110,110,110,110,111,110,111,110,111,110,111,111,111,110,111,111,111,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,109,109,110,109,110,109,110,110,110,110,111,110,111,110,111,111,110,110,111,110,111,110,111,104,104,104,104,106,107,107,104,104,104,107,108,107,107,108,107,106,107,107,107,106,106,106,106,107,108,106,108,107,107,106,107,106,106,106,107,106,106,104,104,104,104,106,104,106,107,107,107,106,106,106,218,217,217,217,217,217,217,217,217,217,217,222,217,222,221,221,222,221,221,221,221,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,108,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,108,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,107,107,107,252,252,252,109,252,252,252,109,107,107,107,107,109,107,109,107,109,109,107,107,109,109,109,107,109,107,109,107,107,107,107,107,109,109,109,107,109,107,109,107,107,107,107,107,107,111,111,110,111,111,111,111,111,111,111,109,110,110,110,110,110,110,110,110,110,110,110,110,111,111,111,111,111,111,111,111,111,104,104,108,108,108,108,108,108,108,108,107,108,108,108,108,108,108,108,107,107,107,107,107,107,107,107,108,107,108,107,108,107,108,109,108,109,105,105,105,105,111,109,109,110,109,110,109,110,110,110,110,110,110,110,110,111,111,111,109,111,110,111,110,111,111,111,111,111,111,111,109,110,110,110,110,110,110,110,110,111,111,111,111,111,111,111,111,111,111,111,111,111,111,110,110,110,110,109,109,110,110,110,110,111,110,111,109,110,110,110,110,110,110,110,110,111,111,111,111,111,111,111,111,111,109,109,109,110,109,110,109,110,110,110,109,110,110,110,110,110,110,110,110,110,110,110,110,111,110,110,110,111,111,111,110,111,111,111,111,111,109,109,109,110,110,110,110,110,110,110,110,111,111,111,111,110,110,110,110,111,110,110,110,111,111,111,110,104,106,108,104,104,108,107,107,107,107,108,106,106,106,107,106,106,106,106,106,106,107,106,108,107,107,107,106,106,107,106,107,107,106,104,106,107,108,104,106,106,106,107,107,106,106,106,106,218,217,221,221,217,217,217,221,217,217,217,221,217,222,217,221,222,221,222,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221,222,221,221,221 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,108,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,109,252,109,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,107,252,107,252,107,252,252,252,252,109,107,109,107,109,107,109,107,109,107,109,107,107,107,109,107,109,107,109,107,109,107,109,107,109,109,109,107,109,107,109,107,107,107,109,107,107,107,107,110,111,111,111,111,111,109,110,109,110,109,110,109,110,110,111,110,110,110,111,110,111,110,111,110,111,111,111,111,111,104,108,107,108,108,108,107,108,107,108,107,108,107,108,107,108,108,108,107,107,107,108,107,107,107,108,107,107,107,107,107,107,108,108,109,105,105,105,105,105,111,110,109,110,109,110,109,110,110,110,110,111,110,111,110,111,111,111,109,111,110,111,110,111,110,111,110,111,111,111,111,110,109,110,109,110,110,111,110,111,110,111,110,111,111,111,110,111,111,111,111,111,111,111,111,110,110,109,109,110,110,111,109,110,110,111,110,111,110,110,110,110,110,111,110,111,111,111,111,111,110,111,110,111,109,110,109,110,109,110,109,110,109,110,109,110,110,110,109,110,110,111,110,109,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,109,109,110,109,110,109,110,110,111,110,111,111,111,110,110,110,111,110,111,110,111,110,111,110,111,110,111,104,106,107,108,104,104,107,108,107,108,107,108,107,107,106,107,106,107,106,106,106,108,106,108,107,107,106,107,106,106,107,107,107,104,106,107,108,104,107,106,106,107,106,107,106,107,106,106,106,217,221,217,217,217,217,217,221,222,221,222,221,217,221,221,221,221,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,108,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,107,252,252,252,252,252,109,109,107,107,107,107,107,109,107,109,109,107,107,109,107,109,109,109,107,109,107,107,109,109,109,109,107,109,107,109,107,109,107,107,107,107,107,107,107,111,111,111,111,109,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,111,111,111,111,111,111,104,108,108,108,108,108,108,108,108,108,108,108,108,108,107,108,108,108,107,107,107,107,108,108,107,107,107,107,107,107,107,107,107,107,105,105,105,105,105,105,111,109,109,109,109,110,109,110,110,110,110,110,110,111,109,110,110,111,111,111,110,111,110,111,111,111,111,111,111,111,111,111,109,110,110,110,110,110,110,111,111,111,110,111,110,111,110,111,111,111,111,111,111,111,111,111,110,110,110,109,109,109,109,110,110,110,110,111,111,110,110,110,110,111,111,111,111,111,110,111,111,111,111,111,109,109,109,109,109,110,109,110,109,110,110,110,110,110,110,110,109,110,110,111,111,110,110,110,110,110,110,111,110,111,111,111,111,111,111,111,111,111,111,109,109,110,110,110,110,110,110,111,111,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,104,106,106,107,108,104,104,108,107,107,107,107,107,107,107,107,106,106,106,106,106,106,106,108,107,107,107,107,107,107,106,107,107,104,106,106,107,104,108,107,106,106,106,107,107,107,106,106,106,106,106,217,221,217,221,217,221,217,221,217,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,108,252,109,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,252,107,107,109,252,109,252,252,109,109,107,107,109,107,109,107,109,107,109,107,107,107,109,107,109,107,109,107,109,107,107,107,109,107,109,107,109,107,109,107,107,107,107,107,109,107,107,107,111,111,109,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,111,111,104,108,108,108,108,108,108,108,108,108,107,108,107,108,107,108,107,108,108,108,107,108,107,108,108,108,107,108,107,108,107,107,107,105,105,105,105,111,105,105,111,110,109,110,109,109,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,111,110,110,111,110,111,111,110,110,110,110,111,110,111,110,111,110,111,111,111,110,111,110,111,111,111,110,111,109,110,109,110,109,110,110,111,110,111,111,111,110,111,111,111,110,111,110,111,110,109,111,111,109,110,109,111,109,110,109,110,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,110,109,109,109,110,110,111,111,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,104,104,106,107,107,108,108,104,107,108,107,108,107,107,108,107,106,107,106,107,106,107,106,106,106,108,106,108,107,107,106,107,106,106,107,104,106,104,108,108,107,107,106,107,106,107,106,107,106,107,106,106,221,217,221,217,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,108,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,107,107,107,107,252,109,252,252,252,109,109,109,107,107,107,107,107,107,109,109,109,109,107,107,109,109,109,107,109,107,109,107,107,107,109,107,109,107,109,107,109,107,107,107,107,107,107,107,107,107,109,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,111,111,111,110,111,111,111,111,104,104,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,107,108,108,108,107,108,107,107,108,108,108,108,107,108,107,105,105,111,105,111,105,105,111,110,109,110,110,110,110,110,110,109,109,110,110,110,110,111,111,111,110,111,110,111,110,111,111,111,111,111,111,111,111,111,111,111,110,111,109,109,109,110,110,110,110,110,110,109,109,111,111,111,111,111,111,111,111,111,111,111,110,111,109,109,109,110,110,110,110,110,110,111,111,111,110,110,110,111,110,111,110,111,111,111,111,111,109,109,110,111,109,109,109,109,109,109,109,110,110,110,110,110,110,111,110,111,111,111,110,110,110,110,110,111,111,111,110,111,111,111,111,111,111,111,111,111,110,110,110,111,111,110,110,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,111,104,106,107,107,108,108,104,104,106,107,108,107,107,107,107,107,107,106,107,106,106,106,106,106,106,107,106,107,108,107,107,106,107,107,108,104,104,107,108,108,107,107,107,106,107,107,107,106,106,106,106,106,106,221,217,217,222,221,222,217,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,109,252,252,109,109,252,252,252,252,252,252,252,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,109,107,252,109,252,109,252,109,109,109,109,107,107,107,109,107,109,107,109,107,109,109,107,107,109,107,109,107,109,107,107,107,109,107,109,107,109,107,109,107,107,107,109,107,107,107,109,107,107,109,110,109,110,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,111,111,111,104,108,108,108,108,108,108,108,108,108,108,108,108,108,108,107,108,108,108,107,108,107,108,107,108,107,108,107,108,108,108,107,108,105,105,105,111,105,111,105,105,111,110,109,110,109,110,109,110,110,109,109,110,109,110,110,111,111,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,110,111,110,110,109,110,109,109,109,110,109,110,110,109,109,110,110,111,110,111,111,111,110,111,109,110,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,110,111,109,110,110,111,111,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,111,111,111,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,109,110,110,111,110,111,111,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,104,106,106,107,107,108,108,104,106,106,107,108,107,107,107,107,106,107,106,107,106,107,106,106,106,106,107,108,106,107,107,106,107,108,104,107,107,108,107,108,107,107,106,107,106,107,106,107,106,107,106,107,106,106,221,217,221,217,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,109,109,252,252,109,109,252,252,252,252,252,252,108,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,107,107,107,107,252,252,252,252,252,252,109,109,109,107,107,107,107,107,109,107,109,109,109,107,109,109,109,107,109,107,107,109,109,107,109,107,109,107,109,107,109,107,107,107,107,107,107,107,107,107,107,109,109,109,109,109,110,109,110,111,110,110,109,111,110,110,111,111,111,111,111,111,107,107,108,108,108,108,108,108,108,108,108,108,108,108,107,107,108,108,108,108,108,108,108,107,108,107,108,107,108,107,107,108,105,105,105,111,111,105,111,105,111,111,110,109,110,110,110,110,110,110,109,109,110,110,110,110,111,111,110,110,111,110,111,110,111,111,111,111,111,111,111,111,111,111,111,111,111,109,109,109,110,109,110,110,110,109,109,109,110,110,110,110,111,111,111,109,109,109,109,109,110,109,109,109,110,110,110,110,110,110,111,111,111,110,111,110,111,111,111,111,111,111,109,109,109,109,110,110,111,110,110,110,110,110,110,110,110,110,110,110,111,109,110,111,111,111,111,111,111,110,110,110,111,110,111,110,111,111,111,111,111,111,111,111,111,109,110,110,110,110,111,111,111,111,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,104,106,106,107,107,108,108,104,104,106,106,108,107,108,107,107,107,107,107,107,106,107,106,106,106,106,106,106,107,107,107,107,106,107,108,104,108,108,108,108,107,107,107,107,106,106,107,107,107,107,106,106,106,106,106,106,221,217,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,109,252,109,252,252,109,109,252,109,252,109,252,252,252,252,108,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,107,252,109,252,109,252,109,252,109,109,109,107,107,107,107,109,107,109,107,109,107,109,107,109,109,109,107,107,107,109,107,109,107,109,107,109,107,109,107,107,107,107,107,109,107,107,107,107,107,107,109,110,109,110,110,111,110,109,111,110,110,111,110,111,110,111,110,109,109,110,107,107,107,107,108,108,108,108,108,108,108,108,107,108,107,107,107,108,108,108,107,108,107,108,107,108,107,108,107,108,107,105,105,111,111,111,111,111,105,111,111,110,109,110,109,110,109,110,110,110,109,110,109,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,110,111,110,109,109,110,109,110,109,110,109,110,109,109,109,110,109,110,110,111,110,111,111,109,109,110,109,110,109,110,110,111,111,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,111,110,109,110,109,111,110,111,109,110,110,110,110,111,110,111,110,111,110,109,109,110,110,111,110,111,111,111,111,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,110,109,110,110,111,110,111,110,111,111,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,104,106,106,107,107,108,108,104,104,104,106,106,106,108,107,108,107,107,107,107,106,107,106,107,106,107,106,106,106,108,107,108,107,107,104,107,108,108,107,108,107,108,107,108,107,107,107,107,106,107,106,107,106,107,106,107,106,106,221,217,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,109,252,109,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,109,252,252,252,252,252,109,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,252,252,252,252,252,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,109,107,107,109,109,252,252,252,252,109,109,109,107,107,107,107,107,109,107,109,107,109,109,109,109,109,109,109,107,109,109,109,107,109,107,109,107,109,107,109,107,107,107,107,107,107,107,107,107,107,107,110,109,110,110,110,109,111,111,111,111,111,110,110,110,111,111,109,109,110,110,107,106,107,107,107,107,108,108,108,108,108,108,108,108,108,107,107,107,108,108,108,108,108,105,105,105,105,105,105,105,105,105,111,111,111,111,111,105,111,111,110,109,110,110,110,110,110,110,110,110,109,110,111,110,111,110,110,110,111,111,111,110,111,111,111,111,111,111,111,110,111,111,111,110,109,109,109,109,110,109,110,109,110,110,109,109,110,110,110,110,110,110,111,111,111,109,109,109,110,110,110,109,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,111,110,109,109,110,110,110,110,111,111,110,110,110,110,110,110,111,110,110,110,109,109,110,110,110,110,111,111,111,111,111,110,111,110,111,110,111,111,111,111,111,111,111,111,111,111,109,109,110,110,110,110,111,110,111,111,111,111,110,110,110,110,110,110,111,110,110,110,111,111,111,110,104,106,108,109,108,104,110,108,104,104,104,106,106,106,108,107,108,107,107,107,107,107,107,106,107,106,106,107,106,106,108,107,107,107,107,108,108,108,108,108,108,108,108,107,108,107,106,108,107,107,107,106,106,106,106,106,106,106,107,221,222,217,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,107,252,109,252,109,252,109,252,109,109,109,109,107,109,107,109,107,109,107,109,107,109,107,109,109,109,107,109,107,109,107,109,107,109,107,109,107,109,107,107,107,109,107,107,107,109,107,107,107,107,107,110,110,111,110,111,110,111,110,111,111,111,110,111,110,109,109,110,109,110,107,107,106,107,106,107,107,107,108,108,108,108,108,108,108,108,107,107,105,105,105,105,105,111,111,105,105,105,105,105,111,111,110,111,111,111,105,111,111,110,109,110,110,110,109,110,110,111,110,109,110,111,110,111,110,111,110,111,110,111,110,111,111,111,110,111,111,111,110,111,110,111,110,111,109,109,109,110,109,110,109,110,109,109,109,110,109,110,109,110,110,111,110,111,111,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,111,111,110,111,109,109,109,110,110,111,110,111,111,111,110,110,110,111,110,111,110,111,110,109,109,110,109,110,110,111,110,111,110,111,111,111,110,111,110,111,110,111,110,111,111,111,110,111,111,109,109,110,109,110,109,110,110,111,110,111,111,111,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,106,110,108,104,104,111,104,107,106,106,107,108,107,108,107,107,107,107,106,107,106,106,106,107,107,106,106,108,107,108,108,108,108,108,108,108,108,108,107,108,107,108,106,107,108,107,106,106,106,107,106,107,106,107,106,107,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,107,107,109,109,109,252,109,252,252,109,109,109,109,107,107,107,107,107,107,109,107,109,109,109,109,109,109,107,107,109,109,109,107,109,107,109,107,107,107,109,107,107,107,107,107,107,107,107,107,107,107,107,110,110,110,110,110,111,111,111,111,111,110,110,110,109,109,109,109,110,107,107,106,107,106,107,106,107,107,107,107,108,108,105,105,105,105,105,105,105,111,105,111,105,105,105,105,105,105,111,111,105,111,111,111,111,105,111,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,111,111,111,111,111,110,111,110,111,111,111,111,111,109,109,109,109,109,109,109,110,109,110,109,109,109,110,110,110,110,111,110,111,111,109,109,110,109,111,110,110,110,110,110,110,110,110,110,111,110,111,111,111,111,111,111,110,109,109,109,110,110,111,111,111,110,110,110,110,110,110,110,111,110,111,110,109,109,109,109,110,110,110,110,110,110,111,110,111,111,111,110,111,111,111,111,109,111,111,111,111,109,109,109,110,110,110,110,111,111,111,111,111,110,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,111,111,106,107,108,104,104,104,107,106,106,106,106,107,108,107,107,107,107,107,107,107,107,106,107,107,107,106,106,106,108,108,108,108,108,108,108,108,108,108,108,108,108,107,106,107,108,107,106,106,107,107,107,106,106,106,107,107,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,109,252,109,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,109,252,109,252,109,252,109,109,109,109,107,107,107,109,107,109,107,109,107,109,109,109,109,107,107,107,109,109,107,109,107,109,107,109,107,109,107,107,107,107,107,109,107,109,107,109,107,107,107,107,110,111,110,111,110,111,109,110,110,110,110,109,109,110,109,110,109,107,106,107,106,107,106,107,106,105,105,105,105,105,111,105,105,111,105,105,111,105,111,111,111,105,105,105,105,105,105,105,111,111,111,111,105,111,109,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,110,111,110,111,110,111,110,111,109,109,109,109,109,110,109,110,109,110,109,110,109,110,109,110,110,111,110,111,111,110,109,109,109,110,110,111,110,110,110,110,110,111,110,111,110,111,110,111,111,111,111,109,109,110,109,110,110,111,110,111,111,111,110,111,110,111,110,111,110,111,110,111,109,110,109,110,109,110,109,110,110,111,110,111,110,111,111,111,110,111,110,109,110,111,111,109,109,110,109,110,110,111,110,111,110,111,111,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,110,109,110,111,110,111,110,111,110,106,106,110,104,107,106,107,106,107,106,106,107,108,107,108,107,107,106,107,106,106,106,107,107,106,106,106,108,108,108,108,108,108,108,108,108,108,107,108,107,108,107,106,107,107,106,106,106,107,106,107,106,107,106,107,106,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222,221,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,108,252,108,252,108,108,109,252,109,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,109,109,109,109,109,252,109,109,109,109,107,107,107,109,107,109,107,109,109,109,109,107,107,109,107,109,107,109,107,109,107,109,107,107,107,109,107,107,107,107,107,107,107,107,107,107,107,107,107,111,111,111,109,110,110,110,110,110,110,110,109,109,109,110,109,110,107,107,105,105,105,105,105,105,105,105,105,105,105,111,111,111,111,111,111,111,111,111,105,105,105,111,111,111,111,111,111,111,111,105,111,111,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,111,111,111,110,111,111,111,111,111,111,111,110,111,110,110,110,111,111,111,110,111,109,109,109,109,109,109,109,110,109,109,109,109,109,110,109,110,110,110,110,111,111,109,109,109,109,110,110,111,111,110,110,110,110,110,110,111,111,111,111,111,111,111,109,109,109,110,110,111,110,110,110,111,111,111,110,110,110,110,110,111,110,111,110,111,111,109,109,110,109,110,110,110,110,110,110,111,111,111,111,111,111,111,110,111,109,110,111,109,109,109,109,110,110,110,110,111,111,111,111,110,110,110,110,110,110,110,110,111,110,110,110,111,110,111,110,109,111,111,111,111,111,111,106,107,108,104,110,107,107,107,106,107,106,106,106,108,107,107,107,107,107,107,107,107,106,106,106,107,107,106,106,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,107,107,107,106,106,107,107,107,106,106,106,106,106,107,107,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,108,109,108,252,108,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,109,109,252,109,252,109,109,109,109,109,107,107,107,107,109,107,109,107,109,107,109,107,109,107,109,109,109,107,109,107,109,107,109,107,109,107,109,107,109,107,107,107,109,107,107,107,107,107,107,109,110,109,110,109,110,109,110,110,111,110,109,109,110,109,110,105,105,105,111,111,111,105,111,105,111,111,105,111,109,111,111,111,111,111,111,111,105,105,105,105,111,105,111,111,111,111,105,111,111,111,110,109,110,109,110,110,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,110,111,110,111,110,111,110,111,110,111,110,109,109,109,109,109,109,109,109,110,109,109,109,109,109,110,110,111,110,111,109,110,109,109,109,110,110,111,111,111,110,111,110,111,110,111,110,111,110,111,111,109,109,110,109,110,109,110,110,111,111,111,111,111,110,110,110,111,110,111,110,111,110,111,110,111,109,109,109,110,109,110,110,110,110,111,110,111,110,111,111,111,110,111,110,111,110,111,109,110,109,110,110,111,110,111,110,111,111,110,110,111,110,110,110,111,110,111,109,110,109,110,110,111,110,111,110,111,110,111,110,111,106,107,108,104,110,107,107,107,106,106,107,107,106,106,106,108,107,108,107,108,106,107,107,106,106,107,107,107,106,106,106,108,108,108,108,108,108,108,108,108,108,108,108,108,107,108,107,108,107,106,106,107,107,107,106,106,106,107,106,107,107,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222,222,222,221,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,108,108,108,108,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,252,109,109,109,109,252,252,109,109,109,107,107,107,107,107,109,109,109,109,109,107,107,107,109,109,109,109,109,107,109,107,109,107,107,109,109,107,107,107,107,107,107,107,107,107,107,107,107,107,109,109,109,109,109,109,110,109,110,109,110,110,109,109,110,110,110,111,111,110,111,105,105,111,111,105,111,111,111,111,111,111,111,111,111,105,105,111,105,111,111,111,111,111,111,105,111,111,105,111,110,109,110,110,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,111,111,110,110,110,111,111,111,110,111,110,111,110,111,110,111,111,111,111,111,109,109,109,109,109,109,109,109,109,109,109,109,109,109,110,110,111,109,109,109,109,110,109,110,110,111,111,110,110,110,110,110,110,109,110,111,111,111,109,109,109,110,109,109,109,110,110,110,110,111,111,111,110,110,110,110,110,110,110,111,110,111,110,111,110,109,109,109,109,110,110,110,110,110,110,111,111,111,110,111,110,111,111,111,111,111,111,109,109,110,110,110,110,111,111,111,111,111,110,110,110,110,110,110,110,109,109,110,110,110,110,110,110,111,111,111,111,111,111,111,111,106,107,108,104,110,107,107,107,106,106,107,107,107,106,106,106,108,107,107,107,106,106,107,106,106,106,107,107,106,106,106,106,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,107,107,106,106,106,107,107,107,106,106,106,107,107,107,106,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,108,252,108,252,108,252,108,252,108,252,108,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,107,252,252,252,252,109,109,252,109,252,109,109,109,107,107,109,107,109,107,109,107,109,107,107,107,109,107,109,107,109,107,109,107,109,107,109,107,109,107,109,107,107,107,107,107,107,107,109,107,109,107,107,109,109,109,110,109,110,109,110,109,111,109,110,109,110,109,110,110,111,110,111,111,111,111,111,111,111,110,111,110,111,111,111,111,105,105,105,105,105,105,111,105,111,111,111,105,111,111,111,109,110,109,110,109,110,109,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,110,111,110,111,110,111,110,111,109,109,109,109,109,109,109,109,109,109,109,110,109,110,109,110,109,109,109,110,109,110,109,110,109,111,110,110,110,111,109,110,109,110,110,111,110,111,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,109,109,110,109,110,110,111,110,111,111,111,110,111,110,111,110,111,110,111,111,111,109,110,109,110,110,111,110,111,111,111,111,110,110,110,110,111,110,109,109,110,109,110,110,111,110,111,111,111,110,111,110,111,110,106,107,108,104,110,107,108,107,107,106,107,106,107,107,107,106,106,107,108,107,108,107,107,106,107,106,107,106,107,106,106,107,106,108,108,108,108,108,108,108,108,108,108,108,108,107,108,107,108,107,106,107,106,106,107,106,106,106,107,107,107,107,106,106,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,108,108,108,108,108,252,108,108,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,252,109,109,109,252,252,252,252,109,107,107,107,109,109,109,109,109,107,109,107,107,107,107,107,109,109,109,107,109,107,109,107,107,109,109,107,109,107,107,107,107,107,107,107,107,107,107,107,107,109,109,109,110,110,110,110,111,110,110,109,110,110,110,110,110,110,110,110,111,111,111,110,111,111,111,111,111,111,111,111,105,111,111,111,105,111,111,111,111,111,105,105,111,111,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,111,111,111,111,111,110,110,110,111,110,111,111,111,111,110,110,111,111,111,110,111,111,111,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,110,109,109,109,110,109,110,109,110,110,109,109,110,110,110,110,110,110,111,110,111,111,109,109,110,109,109,109,110,110,110,110,111,111,111,111,110,110,110,110,111,110,110,110,111,110,111,110,111,111,111,110,111,111,111,111,111,111,111,111,111,110,111,110,111,111,111,111,111,111,111,111,111,109,109,110,110,111,111,110,111,111,111,110,110,110,110,110,109,109,109,109,110,110,110,110,111,111,111,110,111,111,111,111,111,106,107,108,109,110,108,107,107,107,106,106,107,107,107,106,106,106,106,107,108,107,107,107,107,107,107,106,107,107,106,106,107,107,106,108,108,108,104,104,104,104,108,108,108,108,108,108,108,108,108,107,106,106,106,106,107,107,106,106,107,107,106,106,106,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,252,108,252,108,252,108,252,108,252,108,252,108,252,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,107,252,252,252,109,109,109,252,109,252,252,107,107,109,107,109,107,109,109,109,107,107,107,109,107,109,109,109,109,109,107,109,107,109,107,107,107,109,107,109,107,107,107,109,107,107,107,109,107,107,107,110,109,110,110,111,111,110,109,110,109,110,110,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,111,111,105,105,111,111,105,105,111,111,105,111,105,105,111,111,111,110,109,110,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,111,111,111,111,110,110,110,111,110,111,111,111,110,111,110,111,110,111,110,111,111,111,109,109,109,110,109,109,109,109,109,109,109,110,109,109,109,110,109,110,109,109,109,110,109,110,109,110,110,109,109,110,109,110,109,110,110,111,110,111,110,111,111,110,109,110,109,110,110,111,110,111,111,111,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,111,111,110,111,110,111,110,111,111,111,111,111,109,110,109,110,110,111,110,111,110,111,110,110,110,111,110,109,109,110,109,110,110,109,110,111,110,111,110,111,110,111,110,111,111,109,109,109,108,108,107,108,107,108,107,107,106,106,106,107,107,107,106,108,107,108,107,107,107,107,106,107,106,106,106,107,106,104,104,104,104,104,104,104,104,104,104,104,108,108,108,108,108,108,107,108,107,108,106,107,106,107,106,107,106,107,107,107,106,106,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222,222,222,222,222,222,223,222,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,108,108,108,108,108,108,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,252,252,252,252,107,107,107,107,109,109,109,107,107,107,107,107,109,109,109,109,109,107,109,107,109,107,109,107,109,107,109,107,107,107,107,107,107,107,107,107,107,107,107,110,110,111,111,109,110,109,110,109,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,111,111,105,105,111,105,105,105,105,111,111,111,111,111,111,111,111,109,109,109,109,109,110,109,110,110,110,110,110,110,110,110,111,110,111,111,111,111,111,110,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,111,111,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,110,110,109,109,109,109,110,110,110,110,110,110,111,110,111,111,111,111,110,110,110,110,111,110,111,111,111,110,110,110,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,111,111,111,111,111,111,111,111,111,111,110,111,111,111,111,111,111,111,111,111,110,110,109,109,109,110,110,110,110,111,111,110,110,110,110,110,109,110,110,110,111,109,110,111,111,111,111,111,111,111,111,111,111,109,109,109,109,108,108,108,107,107,107,107,107,106,106,107,107,107,106,106,106,107,107,107,107,107,106,106,106,106,104,104,104,104,104,109,109,109,109,109,109,109,109,109,104,104,104,104,108,108,108,108,107,108,107,107,107,107,107,107,107,106,106,107,106,106,106,106,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,252,108,252,108,252,108,252,108,252,108,252,108,109,108,252,108,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,107,109,107,109,107,109,107,107,107,109,107,109,107,109,107,109,109,107,109,107,107,109,109,107,109,109,107,109,107,107,107,107,107,109,107,109,107,109,107,109,109,110,109,110,109,110,109,110,109,110,110,110,110,111,110,111,110,111,110,111,110,111,111,111,105,105,105,105,105,111,110,111,111,111,111,111,111,110,111,111,111,109,109,110,109,110,109,110,109,110,110,110,110,111,110,111,110,111,110,111,111,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,110,109,110,111,110,111,109,109,109,109,109,109,109,110,109,109,109,109,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,109,109,110,109,110,109,110,110,111,110,111,110,111,111,111,110,111,110,111,110,111,111,110,109,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,111,109,110,111,110,111,111,111,111,111,111,110,110,109,109,110,109,110,110,111,111,111,110,111,110,111,110,111,110,111,110,109,111,111,110,111,110,111,110,111,110,111,110,109,109,110,109,108,107,108,107,108,107,108,107,107,106,107,106,107,106,107,106,106,106,107,106,106,104,104,104,104,104,109,109,110,109,110,109,110,110,111,110,111,109,110,109,110,109,110,110,109,109,109,107,108,107,108,107,108,107,107,107,107,106,107,106,107,106,107,106,106,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,108,108,108,252,252,108,108,108,108,108,108,252,108,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,109,109,109,107,107,107,109,107,109,107,109,109,109,109,107,107,107,107,109,107,107,107,109,107,109,107,107,107,107,107,107,107,107,107,107,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,105,105,111,105,105,111,111,111,111,111,111,111,111,111,110,110,111,110,110,110,109,109,109,109,110,110,110,110,110,110,110,110,111,111,111,111,110,110,110,110,110,110,110,110,110,110,110,110,111,110,110,110,109,109,110,110,110,110,111,111,109,111,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,110,109,109,109,110,109,110,109,109,109,109,109,110,110,110,110,110,110,110,110,111,111,111,111,111,110,111,111,111,111,110,109,111,110,110,110,110,110,110,110,111,110,110,110,111,111,111,110,111,111,111,111,111,111,111,111,111,111,111,111,109,109,110,110,111,111,111,111,111,111,110,110,110,110,109,109,110,111,111,110,110,110,110,110,111,110,110,110,111,110,109,111,111,111,111,110,111,111,111,111,111,109,109,109,110,109,108,108,108,108,108,107,108,107,107,107,106,106,106,106,107,107,106,104,104,104,104,104,104,109,109,109,110,110,110,110,110,110,110,110,111,110,111,109,109,109,110,110,110,110,110,110,111,111,104,104,106,108,108,107,107,107,107,107,107,107,106,106,107,106,106,106,106,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,108,108,252,108,252,108,252,108,252,108,252,108,252,108,252,107,252,107,252,252,252,107,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,109,109,107,107,107,107,107,109,107,109,107,109,107,109,107,107,107,109,107,109,107,109,107,109,107,109,107,107,107,107,107,109,107,109,107,109,109,109,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,111,111,105,105,105,105,105,111,111,111,110,111,111,111,110,111,111,110,110,111,110,111,111,110,110,109,109,110,109,110,109,110,110,111,110,111,111,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,109,110,109,110,110,111,110,111,111,111,110,109,109,109,109,110,109,109,109,109,109,109,109,110,109,109,109,110,109,110,109,110,109,109,109,110,109,109,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,111,111,110,111,111,109,109,111,111,111,110,110,110,111,110,111,110,109,110,111,110,111,110,111,110,111,110,111,111,111,110,111,111,111,111,109,109,110,110,111,111,111,110,111,111,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,109,109,111,110,111,110,111,110,111,110,111,109,110,108,108,108,108,108,108,108,108,107,108,107,108,107,106,106,107,110,110,110,110,110,109,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,109,109,109,110,109,110,110,111,110,111,110,111,111,104,104,106,107,108,107,108,107,107,107,107,106,107,107,107,106,106,106,106,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,108,108,108,252,252,252,108,108,108,108,108,108,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,107,109,107,107,107,107,107,109,109,109,109,109,109,107,107,109,109,109,107,109,107,109,107,109,107,109,107,107,107,107,107,107,107,107,109,109,109,109,109,110,110,110,110,110,110,110,110,111,111,111,111,111,111,105,105,105,105,111,111,111,111,111,111,111,111,111,105,111,111,111,110,110,110,111,111,110,110,110,110,109,109,110,110,111,111,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,109,109,109,110,110,110,110,111,111,111,111,111,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,110,109,110,110,110,110,110,109,110,111,111,110,111,111,111,111,111,109,110,110,110,111,111,110,110,110,110,110,110,109,110,110,111,111,111,110,111,111,111,111,111,111,111,111,111,111,111,111,109,110,110,111,111,111,111,111,111,111,111,111,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,111,109,111,110,111,110,111,110,111,111,111,111,109,109,109,108,108,108,108,108,108,108,108,108,108,108,108,110,110,110,110,110,109,109,109,109,109,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,110,110,109,109,109,109,110,109,110,110,110,110,111,110,111,111,111,111,104,106,106,107,108,107,107,107,107,107,107,106,107,106,107,106,106,106,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,252,252,252,252,252,252,252,108,108,108,252,108,252,108,252,108,252,107,252,107,252,107,252,107,252,252,252,107,252,252,252,252,252,252,252,252,252,252,252,252,107,107,109,107,107,107,109,107,109,107,109,107,109,109,109,107,109,107,109,107,109,107,109,107,109,107,109,107,107,107,107,107,109,107,109,107,109,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,105,105,105,111,105,111,110,111,110,111,111,111,111,111,111,111,111,111,109,110,110,111,111,110,109,110,109,110,109,109,109,109,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,111,110,111,110,111,110,111,110,111,109,110,109,110,110,111,111,111,109,110,110,111,109,109,109,109,109,110,109,110,109,110,109,109,109,110,109,110,109,110,109,109,109,109,109,110,109,110,109,110,109,110,109,110,110,111,110,111,111,111,110,111,110,111,110,109,109,110,109,111,110,111,111,110,110,111,110,111,109,110,109,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,111,111,110,111,110,111,110,111,111,111,110,111,110,110,110,110,110,110,110,111,110,111,110,111,110,109,109,110,110,111,110,111,110,111,110,111,110,111,110,109,109,108,108,108,108,108,108,108,108,108,108,111,111,110,110,109,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,109,109,110,109,110,109,110,109,110,110,111,110,111,110,111,104,111,104,107,106,106,107,108,107,108,107,107,107,107,106,107,106,107,106,107,106,223,222,223,222,223,222,104,104,104,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,108,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,108,108,107,107,107,252,107,107,107,252,107,252,107,252,252,252,107,252,252,252,252,252,252,252,252,252,107,252,107,109,107,107,107,109,107,109,107,109,109,109,109,107,107,107,109,109,107,109,107,109,107,109,107,109,107,107,107,107,107,107,107,107,107,109,109,110,109,110,110,110,110,110,110,111,111,111,111,105,105,105,111,111,111,111,111,111,111,111,111,111,105,111,105,111,111,110,109,110,110,111,111,110,110,110,109,110,110,110,109,109,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,111,111,111,111,111,111,109,109,110,110,111,111,110,109,110,110,111,111,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,110,110,110,110,111,110,111,111,111,111,110,110,111,111,111,109,109,109,110,110,110,110,111,111,110,110,110,110,110,110,109,109,110,110,111,110,111,111,111,110,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,109,111,109,111,111,110,110,110,110,110,110,110,110,110,110,111,110,109,110,111,110,110,110,111,111,111,110,111,111,111,110,109,108,108,108,108,108,108,108,108,111,111,111,111,110,111,109,109,109,109,109,109,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,110,110,109,109,109,109,109,109,110,110,110,110,110,110,110,110,111,111,111,111,104,106,106,106,106,107,107,107,107,107,107,107,107,107,107,106,106,106,106,106,223,222,104,104,104,104,104,104,104,104,104,104,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,252,107,107,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,252,252,107,252,107,107,107,109,107,109,107,109,109,109,109,109,107,109,107,109,109,109,107,107,107,109,107,109,107,109,107,107,107,109,107,107,107,109,107,109,109,110,109,110,110,111,110,111,110,111,111,105,105,105,105,105,105,111,105,111,111,111,110,105,105,111,111,111,111,109,109,111,111,110,109,110,109,110,109,110,109,110,109,109,109,110,109,110,109,110,109,111,109,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,109,110,109,110,110,111,111,109,109,110,109,110,110,111,111,109,109,110,109,109,109,110,109,109,109,110,109,109,109,110,109,109,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,111,109,109,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,109,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,109,109,109,110,109,110,110,111,110,111,111,111,110,111,111,110,110,110,110,111,110,110,110,111,110,109,109,111,110,111,110,111,110,111,110,109,110,111,110,111,110,109,108,108,108,108,108,108,108,111,110,110,110,111,110,109,109,109,109,110,109,110,109,110,109,109,111,110,109,110,109,110,109,110,110,110,109,110,110,111,110,110,110,109,109,109,111,110,109,110,109,110,109,110,110,111,110,111,110,111,110,106,108,104,106,106,106,106,107,108,107,108,107,107,107,107,106,107,106,107,106,106,106,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,108,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,107,107,107,107,107,107,107,107,107,252,107,252,107,252,107,252,107,252,252,252,252,252,252,252,252,252,107,252,107,107,107,107,107,109,109,109,109,109,107,107,107,109,109,109,109,109,107,109,107,109,107,109,107,109,107,107,107,107,107,107,107,107,109,109,109,110,110,110,110,111,111,111,105,105,105,111,111,111,111,111,111,111,111,111,111,111,111,109,110,111,111,109,111,110,109,110,109,110,110,110,109,110,110,110,110,110,109,109,109,109,109,110,109,110,110,111,110,110,110,110,110,110,110,111,110,111,111,111,109,109,109,110,110,110,110,111,111,109,109,110,110,110,110,111,111,111,109,109,109,109,109,110,110,110,109,109,109,109,109,109,109,109,109,109,109,110,110,110,110,110,110,110,110,111,111,111,111,111,110,111,110,109,109,109,109,110,110,110,110,111,110,111,111,111,110,109,111,110,110,110,110,111,110,111,110,111,110,111,110,111,111,111,111,111,111,111,109,109,109,110,110,110,110,110,110,111,111,111,111,111,111,110,110,110,110,110,110,110,110,110,109,110,110,111,110,111,110,110,110,111,109,110,111,111,111,111,110,109,109,108,108,108,108,108,108,110,110,110,110,110,110,109,109,109,109,109,109,109,109,109,109,110,110,111,111,110,110,110,110,110,110,110,110,110,110,110,110,110,110,109,110,111,111,109,109,110,110,110,110,110,110,110,110,110,110,111,110,106,107,104,104,106,106,106,106,106,107,107,107,107,107,107,107,106,107,107,106,106,106,106,106,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,107,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,107,107,109,107,109,107,109,107,109,109,107,107,109,107,109,107,109,109,109,107,109,107,109,107,109,107,107,107,107,107,109,107,109,107,252,109,110,109,110,110,111,111,105,105,105,110,111,110,111,109,111,110,111,111,111,111,109,109,110,109,110,110,111,111,110,109,110,109,110,109,110,109,110,109,110,109,110,109,109,109,110,109,110,109,109,109,110,110,111,110,111,110,111,110,111,110,109,109,110,109,110,110,111,110,111,110,111,111,109,109,110,109,110,110,111,110,111,110,109,109,110,109,110,109,110,110,110,109,109,109,109,109,109,109,110,109,110,109,110,110,110,110,111,110,111,110,111,111,109,109,110,109,110,109,110,109,110,110,111,110,111,110,111,111,111,109,110,111,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,109,110,109,110,110,110,110,111,110,111,111,111,111,111,111,110,110,110,110,110,110,110,110,109,109,110,110,111,111,111,110,111,110,109,109,110,110,109,109,111,111,109,109,110,108,108,108,108,108,108,110,110,110,111,110,109,109,109,109,110,109,110,109,109,109,110,110,111,110,111,109,110,109,110,109,110,109,110,110,110,110,109,109,110,110,111,111,110,109,110,109,110,109,110,110,110,110,111,110,111,110,106,107,109,104,107,106,107,106,106,106,106,107,108,107,108,107,106,106,107,106,107,106,106,106,106,106,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,106,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,108,252,108,252,252,252,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,252,107,107,107,107,107,107,252,107,107,107,252,107,107,107,252,252,252,107,252,252,252,252,252,252,109,107,109,107,107,107,109,107,109,107,109,109,109,109,107,107,107,107,109,109,109,107,107,107,109,107,109,107,109,107,107,107,107,107,107,107,107,252,109,109,110,110,111,105,105,105,111,111,109,109,110,110,111,111,111,105,111,109,109,109,110,109,110,110,110,110,111,111,111,111,110,110,110,109,110,110,110,110,110,110,110,109,109,109,109,109,110,109,110,110,111,111,109,109,110,109,110,110,110,110,110,110,111,110,111,110,111,111,111,110,109,109,109,109,110,110,110,110,111,111,109,109,110,109,110,110,109,109,109,109,110,110,109,109,109,109,109,109,110,110,110,110,110,110,110,110,111,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,111,111,111,111,109,109,110,110,111,110,110,110,111,110,110,110,111,110,111,110,111,111,111,109,110,110,111,111,109,109,110,110,111,111,111,110,111,111,111,111,110,110,110,110,110,110,110,110,110,110,110,109,111,110,110,110,111,110,110,110,109,109,110,109,110,110,110,110,111,111,109,109,108,108,108,108,110,110,110,110,110,110,109,111,109,109,109,109,109,109,109,109,110,110,110,110,111,110,110,109,110,110,110,110,110,110,110,109,110,110,110,110,111,111,109,109,110,109,110,109,110,110,110,110,110,110,110,110,111,106,108,104,107,107,106,106,106,106,106,106,106,107,107,107,107,107,106,106,107,107,107,106,107,107,106,106,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,106,106,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222,223,222,222,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,252,252,107,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,252,109,107,109,107,107,107,107,107,109,107,109,109,109,109,107,107,109,107,109,107,109,107,109,107,109,107,109,107,109,107,109,107,109,107,107,107,109,107,252,252,109,110,105,105,105,111,111,109,110,109,110,110,111,111,111,105,111,109,109,110,111,109,110,110,110,110,111,110,111,110,111,111,111,109,110,109,110,109,110,110,110,109,109,109,110,109,110,110,111,110,111,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,109,111,110,109,109,110,109,110,109,110,110,111,109,109,109,110,109,109,109,109,109,110,109,110,109,110,109,109,109,110,109,110,109,110,110,110,110,111,110,109,109,110,109,110,109,110,109,109,110,111,110,110,110,111,110,111,110,111,110,109,109,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,109,110,109,110,110,111,110,111,111,109,110,111,110,111,110,111,111,111,111,110,110,110,109,110,110,111,110,110,110,111,110,110,110,111,110,111,110,111,110,111,109,109,109,110,109,110,110,111,110,111,111,110,108,108,108,110,110,110,110,109,109,111,111,109,109,110,109,110,109,110,109,109,109,111,111,110,109,110,109,110,110,110,109,110,110,109,109,110,110,111,110,111,111,110,109,110,109,110,109,110,109,110,109,110,110,111,110,111,110,106,109,107,106,107,106,107,106,107,106,106,106,106,107,108,107,108,107,107,107,106,106,106,106,107,107,106,106,104,104,104,104,104,104,104,104,104,104,106,104,104,104,104,104,104,106,106,106,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,109,108,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,252,252,252,107,107,107,107,107,107,107,252,107,107,107,252,107,252,107,252,252,252,252,252,252,109,109,109,107,109,107,107,107,109,107,109,109,109,107,109,107,107,107,109,107,109,109,109,109,109,107,109,107,109,107,109,107,107,107,107,107,107,107,107,107,252,105,105,105,105,111,111,109,109,110,110,110,111,111,111,105,111,111,109,110,111,111,110,109,110,110,110,110,110,110,111,110,111,111,111,111,110,110,110,110,110,110,110,109,109,109,110,110,111,111,111,110,109,109,109,109,110,110,110,110,110,109,109,109,110,110,110,110,111,111,111,109,109,109,110,110,110,110,110,110,109,109,110,109,109,109,109,109,109,109,110,109,110,109,109,109,109,109,110,110,110,110,110,110,110,110,109,109,109,109,110,110,110,110,111,111,111,111,110,110,111,110,111,111,111,109,109,110,110,110,111,111,110,110,110,110,110,110,111,110,111,110,111,109,109,109,110,110,110,110,111,111,110,110,110,110,110,110,111,109,110,110,111,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,111,109,109,109,110,109,110,110,110,110,111,111,111,111,110,109,110,110,109,109,110,110,111,111,109,109,109,109,109,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,109,109,109,110,110,111,111,109,109,109,109,109,109,110,109,110,110,110,110,110,110,110,110,110,110,110,109,107,107,107,107,107,106,106,106,107,107,106,106,106,107,107,107,107,107,107,107,107,106,106,106,107,107,106,106,104,104,104,104,104,104,104,104,106,104,104,104,104,104,104,104,106,106,106,106,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,252,108,252,252,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,109,107,109,107,109,107,107,107,109,107,109,109,109,107,109,107,107,107,109,107,109,107,109,107,109,109,109,107,109,107,109,107,109,107,107,107,109,107,109,107,252,107,252,105,111,111,111,109,110,109,110,110,111,110,111,111,111,110,111,110,111,110,111,109,110,109,110,110,111,110,111,110,111,110,111,111,110,109,110,109,110,109,110,110,110,109,109,109,110,109,110,109,110,109,110,109,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,111,110,109,110,109,110,109,110,110,109,109,109,109,110,109,110,109,110,109,110,109,110,109,109,109,109,109,110,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,110,111,111,111,110,111,110,111,109,110,109,110,110,111,110,111,111,111,110,111,110,111,110,111,110,111,110,111,109,110,109,110,110,111,110,111,109,110,109,110,109,110,110,111,110,111,110,111,111,110,109,110,110,110,110,110,110,111,110,110,110,111,109,110,109,110,109,110,110,109,109,110,109,110,109,110,110,111,110,111,111,110,109,108,109,110,109,110,110,111,111,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,109,110,110,111,111,111,110,109,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,109,107,107,107,106,107,106,106,106,107,106,107,106,106,106,106,107,108,107,108,107,107,106,106,106,107,106,107,106,106,106,104,106,104,104,104,104,104,104,106,107,104,106,104,104,104,106,107,106,106,106,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,108,109,108,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,252,252,252,107,107,107,107,107,107,107,107,107,252,107,252,107,252,252,252,107,252,107,107,107,109,109,109,107,109,107,109,109,109,107,109,107,109,107,107,107,107,107,107,107,109,109,109,109,109,109,109,107,109,107,109,107,107,107,107,107,107,107,107,107,252,252,111,111,111,111,109,109,110,110,110,110,111,111,105,111,110,110,110,110,111,111,110,110,110,110,110,110,111,111,111,111,111,111,110,110,110,110,110,109,109,109,109,109,110,109,109,109,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,111,111,111,109,109,109,110,109,110,110,110,109,109,109,109,109,109,109,109,109,110,109,109,109,109,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,111,111,110,110,109,109,109,109,110,110,110,110,111,111,111,110,111,110,110,110,111,110,110,110,111,111,111,110,109,110,111,109,109,109,109,109,110,110,110,110,111,111,111,111,111,111,111,110,110,110,110,110,110,110,110,110,110,110,109,109,109,109,110,109,110,110,109,109,110,110,110,110,110,110,111,110,111,111,110,109,108,108,109,109,110,110,111,111,109,109,109,109,109,109,109,109,110,109,110,109,110,110,110,109,110,110,110,110,110,110,109,109,111,111,110,110,109,109,109,109,109,109,109,109,110,110,110,109,110,110,110,110,110,110,110,109,107,107,107,107,107,107,107,106,106,106,107,107,107,106,106,106,106,107,107,107,107,107,107,107,106,107,106,107,107,106,106,104,106,108,104,104,104,104,104,104,106,107,108,104,104,106,107,106,107,106,106,106,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,108,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,252,108,252,108,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,107,107,109,107,109,107,109,107,107,107,109,107,109,107,109,107,109,107,107,107,109,107,109,107,109,107,109,109,109,107,109,107,109,107,109,107,107,107,107,107,252,107,252,107,252,252,111,110,111,109,110,110,111,110,111,111,111,111,110,110,111,110,111,111,111,109,110,110,110,110,110,110,111,110,111,109,110,109,109,109,110,109,110,109,110,109,110,109,110,109,110,110,110,109,110,110,111,110,110,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,109,110,109,110,110,111,109,109,109,110,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,111,111,110,109,109,110,109,110,110,111,110,111,111,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,109,109,109,109,110,109,110,110,110,110,111,110,111,110,111,111,111,111,110,110,110,110,110,110,111,110,110,110,109,109,110,109,110,109,110,110,109,109,110,109,110,109,110,110,111,110,111,109,110,109,108,108,110,109,110,110,111,111,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,109,110,110,109,110,111,110,111,110,109,109,110,109,110,109,110,109,110,109,110,109,110,110,110,109,110,110,111,109,108,107,108,107,107,107,107,106,107,106,107,106,107,107,107,106,106,106,106,107,108,107,108,107,107,107,107,106,107,106,106,106,104,106,104,104,104,104,104,104,104,106,107,108,104,104,108,107,107,106,107,106,106,106,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,108,109,108,109,108,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,108,252,252,252,252,107,107,107,107,107,107,107,107,107,107,252,107,252,107,252,252,252,107,107,107,109,109,109,107,109,107,109,107,109,107,109,107,109,107,107,107,107,107,107,107,109,107,109,109,109,109,109,109,109,107,109,107,109,107,107,107,107,107,107,107,107,107,252,111,111,111,109,109,110,110,111,111,111,110,110,110,110,110,111,111,111,111,109,109,110,110,109,109,109,109,109,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,111,111,111,111,111,111,111,110,110,110,110,110,109,109,109,109,109,109,109,109,109,109,109,109,109,110,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,109,111,110,111,111,111,111,111,111,109,109,109,109,110,110,110,110,111,111,111,111,110,110,110,110,111,110,111,110,111,110,111,110,111,111,109,109,109,109,109,109,110,110,110,110,110,110,111,111,111,111,111,111,111,111,110,110,110,110,110,110,110,110,109,109,109,109,110,109,110,110,110,110,109,109,110,110,111,111,111,111,111,109,109,109,110,109,109,110,110,110,111,111,109,109,109,109,109,109,109,109,110,109,110,109,110,110,110,110,110,109,111,110,110,110,110,110,110,110,110,110,111,109,109,109,109,109,109,109,110,109,110,109,110,110,110,110,110,110,110,109,108,107,107,107,107,107,107,107,107,107,107,106,106,106,107,107,106,106,106,106,106,107,107,107,107,107,107,106,107,107,106,106,106,104,104,104,104,104,104,104,104,104,106,107,104,104,108,107,107,107,106,107,107,106,106,106,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,222,223,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,109,108,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,108,252,108,252,107,252,252,107,107,252,107,252,107,252,107,252,107,252,107,252,107,252,107,107,107,109,107,109,107,109,107,109,107,109,107,107,109,109,107,109,107,107,107,109,107,109,107,109,107,109,107,109,109,109,109,109,107,109,107,109,107,107,107,107,107,252,107,252,252,111,109,111,110,109,110,111,111,111,111,110,110,111,110,111,110,111,111,111,109,109,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,109,111,111,111,110,110,110,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,109,109,110,110,111,110,111,110,111,110,111,111,111,109,110,109,110,109,110,110,111,110,111,111,111,110,111,110,111,110,111,110,109,111,111,110,111,110,111,109,109,109,110,109,110,109,110,110,111,110,111,110,111,111,111,110,111,111,111,110,110,110,110,110,110,110,111,109,109,109,110,109,110,109,110,109,110,110,109,110,111,110,111,110,109,109,108,108,111,109,110,109,110,110,111,111,109,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,111,110,110,110,110,111,110,111,110,111,110,109,109,109,109,110,109,110,109,110,109,110,109,110,110,110,110,109,109,108,107,108,107,108,107,108,107,107,107,107,106,107,106,107,106,107,106,107,106,106,106,106,107,108,107,108,107,107,106,107,106,106,106,104,104,104,104,104,104,104,104,106,107,104,104,108,107,108,107,108,106,107,107,107,106,106,106,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223,222,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,108,109,108,109,108,109,108,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,108,252,252,252,252,252,107,107,107,107,107,107,107,252,107,107,107,252,107,252,107,252,107,107,107,109,109,109,107,109,107,109,107,109,107,109,107,109,107,107,107,107,107,107,107,109,107,109,107,109,109,109,109,109,107,109,107,109,107,107,107,107,107,107,107,252,107,252,111,111,111,109,109,109,111,111,111,110,110,110,110,111,111,109,109,109,109,109,109,109,109,109,109,110,109,109,109,110,110,110,109,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,111,111,110,109,109,110,110,111,111,111,111,111,110,110,109,109,109,109,109,109,109,109,109,110,109,109,109,110,109,110,109,110,109,109,109,110,110,110,110,110,110,109,109,110,110,110,110,111,110,111,110,111,111,111,111,111,109,109,109,110,110,110,110,110,110,111,111,111,110,110,110,111,110,110,109,110,110,110,110,111,111,111,109,109,109,109,109,110,110,110,110,110,110,111,111,111,111,110,110,111,111,111,111,111,110,110,110,110,110,110,110,109,109,109,109,110,109,110,110,110,110,110,110,110,110,110,110,108,108,108,108,111,110,109,109,110,110,111,111,110,109,109,109,109,109,109,109,109,109,109,109,110,110,110,109,110,109,110,111,110,110,110,110,110,110,110,110,111,110,110,109,109,109,109,109,111,109,110,109,110,110,110,110,110,106,110,108,108,108,108,107,108,107,107,107,107,107,107,107,107,107,107,106,107,106,106,106,106,106,106,106,106,108,107,107,107,107,106,106,106,106,104,104,104,104,104,104,104,104,104,106,108,104,108,108,108,108,107,107,107,106,107,107,107,106,106,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,223,223,223,223,222,223,223,223,222,223,223,223,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,108,109,252,109,108,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,252,252,107,107,107,107,252,107,252,107,252,107,252,107,252,107,252,107,107,107,109,107,109,107,109,107,109,107,109,107,109,107,107,107,109,107,107,107,109,107,109,107,109,107,109,109,109,109,109,107,109,107,109,107,109,107,107,107,252,107,107,107,252,107,252,111,111,109,110,110,111,110,110,110,111,110,109,109,110,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,110,110,111,110,111,110,111,109,109,109,110,109,110,109,110,110,110,110,111,110,111,110,111,111,111,111,110,109,109,109,110,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,111,110,111,110,111,111,109,109,110,109,110,110,111,110,111,110,111,110,111,110,111,109,110,109,110,110,111,110,111,111,111,109,109,109,110,109,109,109,110,109,110,110,111,110,111,111,111,110,111,110,111,110,111,111,110,110,110,110,111,110,109,109,109,109,110,110,111,109,110,110,110,110,110,110,111,108,108,108,108,111,111,109,109,109,110,110,111,111,110,110,109,109,109,109,110,109,110,111,110,109,110,109,110,109,110,110,109,110,111,110,110,110,110,110,111,110,111,110,111,109,110,110,111,109,110,110,111,109,110,110,110,106,108,108,110,108,108,108,108,107,108,107,108,107,108,107,108,106,108,107,107,106,107,106,107,106,107,106,107,106,106,106,106,107,108,107,108,106,106,106,106,106,104,104,104,104,104,104,104,104,104,108,104,108,108,108,108,107,108,107,106,106,107,107,107,106,106,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,223,223,222,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,108,109,108,109,108,109,108,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,252,252,107,107,107,107,107,107,107,107,107,107,107,107,252,107,109,107,107,107,109,109,109,107,109,107,109,107,109,107,109,107,109,107,107,107,107,107,107,107,109,107,109,109,109,109,109,109,109,107,109,107,109,107,109,107,107,107,107,107,107,107,252,107,111,111,111,111,111,111,111,110,110,110,109,109,109,109,109,109,109,109,109,109,109,109,110,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,109,109,109,109,109,110,110,110,110,110,110,110,110,111,111,111,111,111,111,109,109,109,109,109,110,111,109,109,109,109,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,109,109,110,110,110,110,111,110,111,111,110,110,111,110,111,111,111,111,109,109,109,109,110,110,110,110,111,110,111,111,110,110,110,109,109,109,110,110,110,110,110,110,111,111,111,111,109,109,110,109,109,109,110,110,110,110,111,111,110,110,111,111,111,111,111,111,110,110,110,110,110,110,109,109,110,110,111,109,110,110,110,110,110,110,110,110,111,108,108,108,108,108,111,109,110,109,110,110,111,111,110,110,110,110,109,109,109,109,110,111,109,109,110,109,110,109,110,110,110,110,109,111,110,110,110,110,110,110,111,110,111,109,110,110,111,109,110,110,110,110,111,110,106,107,108,109,110,108,108,108,108,108,108,108,108,107,108,107,107,106,107,107,108,107,107,107,107,106,107,106,106,106,106,106,106,106,106,107,108,107,107,106,104,106,104,104,104,104,104,104,104,104,108,108,104,108,108,108,108,108,108,108,108,107,106,106,107,107,106,106,106,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,108,109,108,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,252,107,252,107,252,107,252,107,252,107,107,107,109,107,109,107,109,107,109,107,109,107,109,107,107,109,109,107,107,107,109,107,109,107,109,107,109,107,109,109,109,109,109,107,109,107,109,107,107,107,107,107,252,107,252,107,252,107,111,110,111,110,111,110,110,110,109,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,110,110,111,110,111,110,111,109,109,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,109,109,109,109,109,109,110,110,111,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,109,109,110,109,110,109,110,110,111,110,111,111,111,110,111,110,111,110,111,110,109,109,110,109,110,110,110,110,111,110,111,111,111,110,111,110,109,109,110,109,110,109,110,110,111,110,111,110,111,111,110,109,110,109,109,109,110,110,111,110,111,110,111,110,111,110,111,111,110,110,110,110,110,109,110,110,111,109,109,109,110,109,110,109,110,110,110,110,108,108,108,108,108,108,111,109,110,109,110,110,111,111,111,110,111,110,109,109,110,111,111,111,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,109,109,110,110,111,109,110,109,110,110,111,106,107,107,109,109,110,108,108,108,108,108,108,107,108,107,108,107,108,107,106,106,107,107,108,107,107,106,106,108,106,106,107,106,106,106,106,106,106,107,108,107,106,107,104,104,104,104,104,104,104,104,108,108,104,108,108,108,108,108,108,108,108,107,106,106,108,106,107,107,107,106,106,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,223,223,222,223,222,223,222,223,222,223,222,223,223,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,108,109,108,109,108,109,252,109,109,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,107,107,107,107,252,107,107,107,109,109,109,107,109,107,109,107,107,107,107,107,109,109,107,107,107,107,107,107,109,107,109,107,109,109,109,109,109,107,109,107,109,107,252,107,107,107,107,107,107,107,107,107,252,107,252,110,111,111,110,110,109,109,109,109,109,109,109,109,110,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,111,110,110,110,111,111,111,110,109,109,109,109,110,110,110,110,110,110,110,110,111,111,111,111,109,109,109,109,110,110,111,111,109,109,109,109,109,109,109,109,110,109,109,109,110,109,110,109,110,109,109,109,110,110,110,110,110,110,111,110,111,111,110,110,111,110,111,110,111,111,111,109,109,109,110,110,110,110,110,110,111,111,111,110,110,110,110,110,109,109,109,109,110,110,110,110,111,111,111,109,110,109,110,109,110,110,110,110,110,110,110,110,111,111,111,111,111,111,110,110,110,110,109,110,111,110,110,110,109,109,109,109,110,110,110,110,110,110,108,108,108,108,111,111,110,109,110,110,109,110,111,110,111,110,111,110,109,109,110,110,111,109,109,109,110,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,111,109,109,109,110,110,111,111,109,109,110,110,110,106,107,107,108,109,109,110,108,108,108,108,108,108,108,108,108,108,108,107,108,106,106,107,107,108,108,107,106,107,107,108,106,106,106,106,106,106,106,106,106,108,106,108,104,104,104,104,104,104,108,104,104,104,107,108,108,108,108,108,108,106,108,108,108,107,106,106,107,107,106,107,108,108,106,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,252,109,109,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,252,107,252,107,109,107,109,107,109,107,109,107,109,107,109,107,109,107,109,109,109,107,107,107,109,107,109,107,109,107,109,107,109,107,109,109,109,107,109,107,252,107,252,107,252,107,107,107,252,107,252,107,252,252,252,111,111,110,110,109,110,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,109,110,109,110,109,110,109,110,110,111,110,111,110,111,110,109,109,109,109,110,110,111,109,110,109,110,109,109,109,110,109,110,109,110,109,110,109,110,109,109,109,110,109,110,109,110,110,111,110,111,110,111,111,111,110,111,110,111,110,111,110,111,110,109,109,110,109,110,110,111,110,111,111,111,111,111,110,111,110,111,110,109,109,110,109,110,110,111,111,111,109,110,109,110,109,110,110,110,110,110,110,111,110,111,110,111,110,111,111,110,110,110,109,110,110,111,110,111,110,111,110,109,109,110,109,110,109,110,110,108,108,108,111,111,109,110,109,110,109,110,110,109,110,111,110,111,109,110,110,111,111,109,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,111,110,111,109,110,109,110,110,111,111,111,109,110,109,106,106,107,107,108,108,109,109,110,108,108,108,108,108,108,107,108,107,108,107,108,107,108,106,107,107,108,108,107,106,107,107,108,108,107,106,107,106,107,106,106,106,106,104,104,104,104,104,104,106,104,104,104,104,107,108,108,108,108,108,108,108,106,107,108,107,108,107,106,106,107,106,107,107,108,108,106,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223,223,223,222,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,109,108,109,108,109,109,109,109,109,109,109,108,109,108,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,107,107,107,107,107,107,109,107,109,109,109,107,109,107,107,107,109,109,109,109,107,107,107,107,107,107,109,107,109,109,109,109,109,109,109,107,109,107,252,107,252,107,107,107,107,107,107,107,107,107,252,107,252,252,252,111,110,109,109,109,109,109,109,109,109,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,111,110,111,110,111,110,111,111,111,111,111,111,111,111,111,109,109,109,110,109,110,110,110,110,111,110,111,111,111,109,109,109,110,110,111,109,109,109,109,109,110,109,109,109,109,109,109,109,109,109,110,109,110,109,110,109,110,110,110,110,110,110,111,111,111,111,110,110,110,110,111,110,111,111,111,111,111,109,109,109,110,110,110,110,111,111,111,111,111,110,110,110,111,110,111,110,109,109,110,110,110,110,111,111,109,109,110,109,110,110,110,110,110,110,110,110,111,111,111,111,111,111,110,110,110,110,109,110,111,110,110,110,110,110,110,110,109,109,110,110,110,110,108,108,111,111,109,109,109,109,110,110,110,110,110,110,111,111,109,109,110,110,111,109,109,109,109,109,109,109,109,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,109,109,110,110,111,111,111,111,109,109,106,106,107,107,108,108,109,109,110,110,108,108,108,108,108,108,108,108,108,108,108,108,108,107,106,106,107,107,108,108,106,106,107,107,108,108,107,106,106,106,106,106,106,106,106,104,104,104,104,108,104,104,104,104,107,108,108,108,108,108,108,108,108,108,106,108,108,108,108,106,106,106,107,107,108,108,108,106,106,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223 +,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,109,109,108,109,108,109,252,109,252,109,252,109,252,109,252,109,252,109,252,109,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,107,107,107,252,107,252,107,107,107,109,107,109,107,109,107,109,107,107,107,109,107,109,107,109,107,109,107,109,107,109,107,109,107,109,109,109,109,109,107,252,107,252,107,109,107,107,107,252,107,252,107,252,107,252,107,252,252,252,110,109,109,109,109,110,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,111,110,111,110,111,110,111,110,111,110,111,110,111,110,111,111,111,111,111,110,111,252,109,109,110,109,110,109,110,110,111,110,111,110,111,109,109,109,109,109,110,109,110,109,110,109,110,109,110,109,109,109,110,109,110,109,110,109,110,109,110,109,110,110,110,110,110,110,110,111,111,111,111,110,110,110,110,111,110,111,111,111,111,111,109,109,109,110,110,110,110,111,111,111,111,111,110,110,110,111,110,111,110,109,109,110,110,110,110,111,111,109,109,110,109,110,110,110,110,110,110,110,110,111,111,111,111,111,111,110,110,110,110,109,110,111,110,110,110,110,110,110,110,109,109,110,110,110,110,108,108,111,111,109,109,109,109,110,110,110,110,110,110,111,111,109,109,110,110,111,109,109,109,109,109,109,109,109,109,110,109,110,110,110,110,110,110,110,110,110,110,110,110,109,109,110,110,111,111,111,111,109,109,106,106,107,107,108,108,109,109,110,110,108,108,108,108,108,108,108,108,108,108,108,108,108,107,106,106,107,107,108,108,106,106,107,107,108,108,107,106,106,106,106,106,106,106,106,104,104,104,104,108,104,104,104,104,107,108,108,108,108,108,108,108,108,108,106,108,108,108,108,106,106,106,107,107,108,108,108,106,106,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223]} +); diff --git a/apps/animclk/animclk.pal b/apps/animclk/animclk.pal new file mode 100644 index 000000000..d33bfcdb9 Binary files /dev/null and b/apps/animclk/animclk.pal differ diff --git a/apps/animclk/animclk.pixels1 b/apps/animclk/animclk.pixels1 new file mode 100644 index 000000000..7f0dbf944 --- /dev/null +++ b/apps/animclk/animclk.pixels1 @@ -0,0 +1 @@ +                                                                                                                                                                                                                                                                                          ʘ˘̛̛̘̘̘˛ʛ̛̛̛̛̛̛̛̜̜̜蕕蕐̛̛̛蓖̛蓕̛薔̜萐˝蓐̜萐̜萒萐萒̝ \ No newline at end of file diff --git a/apps/animclk/animclk.pixels2 b/apps/animclk/animclk.pixels2 new file mode 100644 index 000000000..f4a4ee077 --- /dev/null +++ b/apps/animclk/animclk.pixels2 @@ -0,0 +1 @@ +萐蒒蒒蒒蒒̜蓐蒒̝蕕qrrrrrr̜萒qqqqqqqrrrrrrrrqqrrrrr̝蕕sssstssstsqqqqqqqqrrrrrrrrrrrrrrrrr̝qqqqqtststtttttttuuuuuuttqqqqqrrrrrrrrrrr̝qqqqqqqqstststtttttutututuuututututututqqqqqqqqqq̜qqssssssssststtttttttttuuuuuuttttttututuuuuuuuuuuuuu̝–qqqtqqqssuuuuututuutsttututututttututututututututututuuuuuu–sstussssttuuutuuuuttuuutuuttuuutttttutttutttuuutuuuuuuuuuuusstusssttuuututuuutttutuuutuututtutututuqqqrqrrrrrrrrrrrrrssstusststtuuttuuutttttuuuuuuustuqqqqqqqqqtttttttttttttuuuuspqqqsssussssttuuttuuuuttutuuutuussttsusststtututuststtttutusupqqsssuststttuutuuttututuuuuuuussttuttttuussttussssttttuustppqqpppsststststtuuttutuuutututuuusttututstututuusssuutsttustptpqpssssssttttttututttutuuuuuusstttuutstuuutuuuststttttuuputppsspppssststtttutuuutututuuusssttutuststtutsuutstststsusupuppppptsttutssttssssttttutuuuuuuuuuussssttttustuttttsuussttttuustptuptsssttusustsuststtutututususttussssstsssusttusttusutututuutsupuptssstttsuuttussstttuuuttusttussssstssssstsutuuuttsttuuututputststtustuutustsssttuutsussststststsssuststtutuuuuuuuuuutuptsssttttuuttussttstuttustssssssstttssssstssttuutuuuu"$02367:;>>05:>%&)),0235699<=?ssstststssssstststtuuuuu"#%&'()*,-./ "#%'(*,-/ !!"##$%&&''()**+,,-.02478;=?Ɯ$%( "#%&()+,./--.././Ɯ)*+,-./++--./Ɯ-../ &%&&'&'(Ɯ,- "$%()+- !"#%&'()//5689;<>?0134679:<=?024:<=?02467ƛ/ "#&'*+- #%(*-/>?014589<=?02367:;=?014589<=?Ɯ)*+,--// !"#$%& !"#$%&()*,-./::;;<<==>>??KKLMNNO5556!"##%%&&''((**++,,--// !##%%'(**,,./?02367:;>>;EGGHIJJLLNNO45465767 "$&)*-/!!""##$$%%&&''(()**++,,-..// !#$%&()*+-./566>??@ACDEFHIJKMNO344 !!""##$$%%&&''(())**++,,--..//001122<>?@AACCEEGH . "%'*,/ !!""##$$%%&&''(())**++,,--../0111=>??@ABB !"#$%&'()*+,-./ !!""##$$%%&&''(())**++,,--..//001<>=>>,,,,,,, $'+/ !"#$%&'()*+,-./ !!!"""##$$%%%&&'''(())**+++,,,--..//0011<==--------- #(+/ ! ! !!"!""##$#$$%%&%'&''(')())**+*++,,-,--.././0101122< !!!!!!! !!!!""""####$$$$%%&&&&''(((())))****++,,,,---...///0111122334"" ! !!"!#"##$#$$%$%%&%&&''('(())*)**+*++,+,,--.-.././deeff0011213233545""""#$$%%%%&&&&''(((())))**++++,,,,----..///abbccdde00111223334445%&%()())*)**+*++,+,,-,--.-.././/eeff``aa00112233438(+,,,,----....////aabbccdde0011222334455667././//fg`abcdef``00112233445565778788:eefffgg`01122334455566778899::;;;0112233445566778899::;;<<==>566778999:;;<===>??@@BB;;<<==>>?YZYZZ[@BBEEƀXXYYYYYYZ@BDFHKMO2Ɔƀ@BDEHILMO@CEHJMOOƎ@@AABBCCCDDEEEFFGGHHHIIJJJKKLLMMMNNOO=??012244667899;;==>?@@@AABBBCCCDDDEEFFFFGGHHFEFFGFHGHHIHJIJJKJKKLKLLMLMMNNONOb7c89:::fd6778899:::>>>>??A@?B?AA@ABABCCDBDEFFGGHHFFFFGGHHHHIIJJJJKKLLLMMMNNNOO2425556779fd6778899:::::=>==>>>>>@>?ABAABCCCDCDFFFFGGHHEEFFGGHHIIJJKKLLMMNNOOO/deeeeeeefd67fd67787899:::::=====>>>??????@?A?ABDDEEF@FFGGHH@ABCDEFFHHIJKLMNOdde/ed/dddedfe/ffeecc6fc88f8f99=:::=======??????@=@=ACDCDEEFFFFGGHHKIHL@NLMd//e/ee/ed/dddedfe/ffeecc6fc88f889:9::<<<========>????=A=D=EEFFFFGGHHEJDFc/dddddde/ed/dddedfe/ffeecc6fc88ff888::9:9>99e:==>==>>>>?>??@@@^]@_B\AHƂcdddeeee/ed/dddedfe/ffeecc6fc88f778899:::<=:===>>>??>?=>>?>Z>^[Z^[^\]]ƀcccdde/ed/dddedfe/ffeecc6fc88f778897:9:=:<=>==>>??>>>>>?>[[\Z\\[\]]^d/dddedfe/ffeecc6fc88ffd6778899:::<<<=====>>>?<==>>\>\\]\^^^^FGGHHIĈ787889899c9:9:9::;:;:;;;;<;<<=<=<===<==???=>>???]\]]^^]^^^__^_@AABBCCDDEEFFGGHĈ9999:9::::;d;;;;;;<<<<<<=<======>>>>>???\>?\]\]]^^^^@^A@BACBCCDDDDEEEFGGG:::;:;:;;<;<;<<<<=<=<=====>=>>>??>>????\]]\^^@BAB@BABCCCDDCCDDDDEEFFFGGGČAAB;;;;<<<<<<<<========>>>>>=>>>>>>?0???5?ŀƏƄ]^^\]@A]DBBDCCDDDDFDDEEEFFFFGGHHIIIIBBN<=<=<====>=>=>=>>>>?>>>>>>?>?>=><=?X???\AA]B@B\@C@ECEFFFFFEFFEEFFGFHGHHIIJIJJKKLKLLMMNMNNOOO@O@@@A@BABBCCDƈMMM>=>>>>>>>>??????<<===?==>>>?>>>=>>;=XXXXY;>Y?YYC[AAB\D\ABDACBDCDADCDDDFFGFGFFGGFGGGGHHHHIIJJJJKKLLLLMMMMNNNNOOO@O@@@AAAABBCCDDDDEFFFGGHHIIIIJJKKLLLLLLLMMMM>?>>?>>?>?>>>=?===?=>=?=??>>=>==>X??Y>Y=ZZA@ZBC@CCCBDCDEBDEECDFDEFEGGHHGHHGHGHHIHIIJIJKJJKKLKLLMLMMNNONOOOOO@O@@@AABBCBCCDDEEFEFFGGHHIHIIJJKKLLL>?===??>>?>>>==<=====>=?==???>:>:=>YXW>VX@ZZ@BABCDDCBCDDDDEEFEDEFEFEEFFGIJHHJHIHIIIIIIJKKJKKKKLLLLMMMMNNNNOOOOOOO@@@@@A>?SSR=>?R>???=STT>>>>>>>?>>>??>>>>>U>=>VWXYABCDCCEDEDEFEFEFFFGGFGGGGHHGIHIHJJJJJJJJKJKKJLKKKLLLMLMLMMNMNNONONOOO@O@AQQ@??RR>RR@>RSR<>S=>@>?B>@=>U>V?VUVWW@ACDCEDDEEEFFFHFGGGGHHIHIHIHIHJIJJIKKKKJKJJKJLLKLLKLLLLMMMMNNNNONOOOOO@O@AAB@Q@QARRAR@S?ASSBSSS>@TSCACB?C@@UAVAWAEVEBCEEFFFGFFFGGHGHIHJIJJIIIJIJIJKJJJKKJLKLKLKJKKLMKLLLLMLMMNMNNNNONONOOO@O@@@AABCCAAARAARRBBCCSDTCBATS@AEECDDDDDEFBECCGFGGGGGHHGGGGGGHIHJKJJJJJKJKJJJJJKKJKJKLKKLKKLKKLKLMLLMMMMMMNMNNNNONOOOOO@O@@@@@AAABCCDBA@BBA@AABDDEDEDDEDCCEGCFFEGFFGHGFEIFGHGHHHHHHHIIIIIJJJJKJJKJKKJKKKKKJKKKKKKKLLKLMLMLLLLLMLMMNMNMNNONONONOOO@OO@@ABBCCDEABABBCCDCCDEDDDEDEFGHGGFHFHGIGFGGGHHIHIHHHIHIIIJHIIIJKIJJKKKKKLKKLKKKKKKLLKLKLKLLLMLLMMLMMMMNNNNNNNNOOOOOO@O@@@AABCCDDCCBCCCCCCDDDEDEEFEEFHGHHHGHGIHGHHIIJIGJIIIIIIIJIJIJKJJJJJJJKKKKKLKKLLKKLKMLLKLMLLLLMMLMMMNMNNNNNNONOOOOO@O@O@@@AABBCDDECCCCCCDCCDDDEEEEGEFGFGHGHHHIIHIIIHJHIHIJJJJIIIJJIKJJJJJJJJJKKKKKKKKLLLLLMMLMLLMLNMLMLMNMNNNNNNOOOOOOOOO@@@@@@@AABBCCDDEOCCCDDDDDDEEEDEEEFEEFGGGHHHHIIHIIIIJIJIJJJJJIJIJKJKIJKKJJJKJKLKLKKKLLMLMLMMMMLMNMNMMMNNMNNONONOOOOO@O@O@O@@@A@AABBCCDDEEFODDCCEEFEEFEFEFFFFGGGGFFGHHIHGIHIJIIJIJJJKKJJKJJKJKJKKKKKKKJKLKLLLLLLMLMMMMMMMNMNNNNNNNNNOOOOOOOOOO@@@@@@@@AAAABBBBBBCCDDEEFFGHFFGEGFFGGGGFGHGGHGHHGHGGFHHIIHIIIIJJJJJJJKJKKKKJKKKKKLLKKLKKLLLMLMLMLMMNMNMNMNNONONONOOO@O@O@O@O@@@@@AAAABBCCDDEEFFGGHHHGGGHGIGGIHHHHHHIHHHHIIGHIGHIHIIIIIJIJJJJJJKJKKKKKKKKLLLLLLLLMMMMMMMMNMNNNNNNONOOOOOOOOOO@O@@@@@@@AAAABABBBBCCCCDDDEEFFFGGHJJHGIJHIIHIIIIIHHHHHHJJIIIIJJJIJJJKJKKJKJKJKKLKLKLKLLLLMLMLMLMMNMNMNMNNONONONOOOOOOO@O@O@O@O@@@@@AABBBCBCBCCDCDDEDEEFEFFGGHHIhLHIJJJIKJIJIJIJJJJJJJJJJKJKJKKKKKKKKKKKKKLKLLLLLLLLMMMMMMMMNMNMNNNNNNNNOOOOOOOOOOO@O@@@@@@@@@@@AAAABBBCCCDDDEEFFGGGHHHnhhJKLJKKKKKJKKJJJJKKLLKKKKKKLLKKKKLLLKLKLLMLMLMLMLMMNMNMNMNNNNNNONONONOOO@O@O@O@O@OO@@@@AAABBCCCDCDCDDEDEDEFFGGHHHIIohohLLLLKLLLKKLKLLKKLLLLLMLMLLLLLMMMMMMMMMMMMMMMMMNMNMNNNNNNNNOOOOOOOOOO@O@O@@@@@@@@@AAABBBCCCCCCDDDDEEEEFFFFFFGGGGHHINOhjhjjKKLLLKLLLLLMMLLLMMMMLLMLMLMMMMMMMMMMMMNMNMNMNMNNNNONONONOOOOO@O@O@O@O@O@@@@@@@A@AAABBBCCDDDEEEFFGGGHHHIINNOOoohjjLLKKLLMLLLLMLLLLLMMMMMMMMMMMMMMMMMMMMNMNNNNNNNNOOOOOOOOOOOO@O@@@@@@@@@@@AAABBBBCCCDDDEEFFFFGGHHHIIINOOjhkkjjKLLLLLMMMMLMLMLMNMMNNMNMNMNNMMNNMMNNMNNONONONOOOOOOO@O@O@O@O@O@O@@@@@A@AABBBCBCBCCDCDDDDEEEFFFGGGHHHIIIJJJlhkjjjjLLLLLLLMMMMMMMMMMMNMNMNNNNNNNNNNNNNONOOOOOOOOOOOOO@O@O@@@@@@@@@@@@@AAAAABBBBBBCCCCCDDDEEEEEFFFGGGHHHIIIIJJlhkkjjjLLLLMMLMLMLMMMMNNMMNNMNMNMNNONONONOOOOOOO@O@O@O@O@O@O@@@@@AAAABABBBCCCDDDEEEFFFFGGMMMNIIIJJJhkkkkjjjLLLMMMMMMMMMMMMMNNNNNNNNONONOOOOOOOOOOOOOOOOO@O@O@O@O@O@O@@@AAAABBBBBBBBCCCDDDDEEEFFFGGGGNNNOOklkkjkjjjLMMMMMMMNMNMNMNNONONONOOOOOOO@OOOOOOOOO@@@AABBBBCCCCDDDEEEFFFFGGGHHHCIOkkkkkjjjjMMMMMNNNNNNNNNNONOOOOOOOOOOOOO@@@@@AAAAAAABBBBCCCDDDDEEEFGGGGHHHIjkkkjkjkjjMNMNNNNONONONONOOOOO@O@OOOO@@AAAABBEFGHIJKMNOGGGGHHHIkkkkkjjkjjNNNNNNOOOOOOOOOOO@@@@@AAAAAAHIKMOCHjkjkkkjkjjjONONOOOOOO@OO@@AAAABBBBBCCCDFFFGGGjjjkkjjjjjjjOOOOOOOOO@@BGKO@AAAABBBBCCCCDDDEEkljkkkjkjjjjOOOOOOO@@@@AAAABBBBCCCDkkkjkkkjkjjjjOO@@@@@@@AAAABBBBCklkjjkjkjkjjjjOO@O@@AAAABBBBCCCDDkkkjkjkjjjjjjj@@@@@AAAABBBBCEEkkkkjkjkjkjkjjj@@AAAABBBBDlkkkjjjjkkkjjjjAAAABBBBCCDDDEEklkkjjjkjkkkjkjjBBBBCCCDDDDDklkkjjkkjkkjjjjjjBBBCCCCCklkljkjkkkkkjkjjjjCCjCCDCDCDDEkllkjjjjkjkjkjjjjjCCCDDkllljkjkkkkkjkjjjjjDDDDDEEDEEFEkllkkjkjkjlkkjjjjjjjDDDEEFjlklkljkjllkjkjkjjjjEEFEFlllklkkjjklkkkjjjjjjjEEllklklkljjkljkjkjkjjjjEEFEFFFFGkllllklkkjjlkkkjjjjjjjFFFGGhhhhhhhlkljljkjkjkjkjjjFhhhhhhhhlkkjlkkjkjjjjjjjoomhjklhhlkkjkjkjkjkjkjjnnnnhjklhhkkkkkkkjkjjjjjjGHGnnnonhjkkhhhkkkkjkjkjkjjjjnnnnohjkllhhkkkkkkkjjjjjjjHnonnnhjkkhhhhjkkkkjkjkjjjjjnonnnhjklhhhjljkkkkkkjkjjjjjnooohjjllhhhjjjlkkkkjjjjjjjjooonhjklhhhkkjjjkkkkkkjjkjjjjnooononjlhkkjkjkjjkkjkjjjjjjjoonnnnonjkkjkjjjjkjlkkkjkkjjjjnononohomlkkjkjjjjkjlkjjjkjkjjjnnnnohomllkkkjkjjjkjlkkjkkljjjjnonohomlklkkjkjkjjjljkjjjkkkjkjjnnhhojlllkkkkjjjkkjjjkkjjkkjjjjjjnhjlhmllklkkjkjkjkkjkjkjjkkjjkjjjjkmhmklllkkkkkjjjkkjjkkkjkjkjkjjjjkljhhlklllklkkjjjlkjjjkkjjjkkkjjjjjlhhhjhlklllkkklkkjkjjjkkkjkkkjkjjjjhnnhjkkllhhlklkkjjjkjjjlkkjkkjjkjkjjhhhhhoomhjjkkllhhhllkkjjjkkjjkkkjljljjjjjjhhhhhhhhhhhmnmhjkjkkllhhhhkjkjkkkjjklkkjjkkjkjjjhhhhhhhhhhhjhnnhjjjkkllllhhhhhjjjkkkjjkkkkjljkjjjjjhhhhhhhhhjklhnhjkjkklkllhlhhhhkjkjkkjjjjlkjlkjkjkjjjhhhhhjhjkkhhjnnhjkkkkllllhhhhlkjjkkkjjjjlkjljkkjjkjjjhhhjhhhjklhjjnonhhjjkkllhhhhjlkjjjkjkjjjjkjkkjkjjjkjjhhhhhhhjkhjjjnnnhjjkkllhhhhkkkljjjkkkjjjkkkjlkkkjjkkkjhhhhhjkhjkjjjnonohhhhjkkhhhklkklkjkkkjjjjkljlkkjkjjjkjjhhhhjhjkkkjjjonnnooonhjlhhlkkkkljjjkjjjjjjkjlkkkjjkjkkjhjklhjjjkkjjjjnonononohjklhhklklklkkjkjkjjjljlkkjkjjkkkhjklhkjjkjkjkjjjnnononohjjklhhlkkkkkkkkjjjjjjjlkkkkkkjkkhjjkhlkjjjkkkjjjjjnononohhjkkllhklklkklkjkjkjkjjjljlkkjkjjkhjhllkkjkjkjkjkjjononoohjkkllhhjklkkkkkkjkjjjjjjkjklkkjkklhhkllkkkjkkkjjjjjjnononohjjkkllhjjklkkkkjkjkjkjjjjkljkkjklhkklklkkjkjkjkjkjkjjonooohjjkkllhhjjlklkkkkkkjkjjjjjjkkkkjklhllllkkkkjjkkkkjjjjjjnonohjjkkllhhhjjjlklkkkkjkjkjkjjjlklkkhkllklklklkkkkjkjkjkjkjjooonhjlmlhnlhhhjjjlklkkkkkkjkjjkjjlkkkkllllllllklkjlkkkjjjjjjjknonononojnlhhohkjjklklkkkkjkjjjkkjjlklllllllllklkljklkjjjkjkjkjkonoooooojklhhhkjjjjklkkkkkkkkjkkkjjjlllllllllllllkjklkjjkkkjjjkknmnonononjjnhkjkjkjjklklkkjkjjjkkjjjllllllllllklklkjkkjjjkjkjkjkjmoooooojklhnkkkjkjjjlkkkkkkkkjjjkkjjlllllllllllllllkkkjjkkkjjjjjkknononojklhnkkkjjkkjjjlklkljkkjjkkkjjjlllllllllllllklklkjjkkkjjjkjkkoooooojklhnkkkjjkkkjjjlkkkjjkjjjkkjjjjlllllllllllllllkkjjjkkkjjjkkkjnononjklhnklkkjkjkkkjjklklkkjkjkjkjjkjllllllllllllklklkjkjjkjjjkkkkjjooooojklmnlkkkjjkkkjjjjklkkkkkkjkkjjkkjlllhhhhlllllllllkjjjjkkjjkkjjjnonoommmllklklkkjjjkkkjlklkkkkjkjjjkjhhhhhhhhhhhllllllklkljkjkjkjkkkjjoooommmmlllkkkkkjjkkkjjjkkkkkjjjjhhhhhmmmmmmmmmhhhhllllklkkkkkkkjjkjjjjnonmmnmlklklklkkjkjkjkjjjkjjhhhhhmmnmnmnnonomnmnmnnmmmklklklkkkkjkjkjkjj \ No newline at end of file diff --git a/apps/animclk/app-icon.js b/apps/animclk/app-icon.js new file mode 100644 index 000000000..f904072e3 --- /dev/null +++ b/apps/animclk/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+i4AFnYHGBBIAPDA0dAH4A/ABtBFtlk0uALlml0uBF1uAvQvtvQvroGAF4NWdteARwIvsXwNWq1BAFEdwK+CF9VBF4d6F9SOBR4OAF1OIF4KOB0opjwV6vd7rrtCFwIvlwN70q6BFQN6RwIEBsoAHrwJIACGBdINWvTtDAoIvINgIuYxAvBwAsCLwIjB0glGxKbCMDGCvYvBDwItBGYdWxIAExBpBp9dx4LFAAuPx+IxAQELoK9BE4S+CLgKQCC4IAD1gKBp9WBQoAFxOCE4WCAAIvB0uBWgIuCq2kAoIiBp962YAECIVPqFWBYoAEWQIAH0qNBLwYDBLwRfCF49Pp+BAIIuI1gnBvYADAoIBC0q9BAAWl0hiBp4nBDwoRBLwOzNwOtBgms1ouBq4mBAAQECRwICBGAJeCvQEEldeAAZxESIIzBBgeCq9dFwKKEqwuDvS/CMAQCCXgJiBp9dAAQFBFYUrAAgrBAAszmddq4ABJwI0CFANVXIjsCAIU5nMznNXLYIpBlksmUyq0yBgIBBroDBAwQKCJAMrJIIiBDYJNBAoILBqoJBHIIaDJYIABJgIsBAAIKBAAI7CAgIJBHgNVqsrkgCBPAgwBAAMkDARYBJ5AAFGgcrFQOIAALBFEQQwBbQQ3BAASGCqokDLAwACToKfDAYRyCwQzBFYaODfAOl0q/BR4I1BL4IcDAYIyDmUOhw4DN4IABr1eLQJkDxGsAAWBLAQxBA4L3BYQQoChEIFAIABFAuCKoWIAYYqE1oAB2ez6+sxGrLwOr6HW63XBQOrFYQxBFIRRBEgglBFogqEFYQtC2YODGAWl1nQGQXWU4geBAYNeE4YXD0mBFIoqBJ4RpG1YwEAQOBvQNBZYQHBwI1EBIQABcAOsFoaOCSw4XFeIkr0mlwACBBYYgBCooSBbwIrDwOIB4oAFMAITC6GrL4N60gCBAgSFBRAQCDvUkkgwBruIw+CQIYsHXQQAHwGAF4YTB5+kMwgABqp0Cp+BNgwsEFpQABD4JdDFQgxCAgOAAYIwCqzgEQwgsLAAWkEAIACGIQ2DNQmkYIUrOIRaEFx/QXA4oCY4g4CFwSRBB4SJOX4wiBMIYpDFwhfCGAtPSYJeCACC5FLoYEDNQYJBSAcqAQNWF6oeBXQgrCAoIzBAIKQFGAeAdwIAQDwNVqt6vLeDLQYzDFwVWfAYHCCIYAOwAaEEwJbCLQSTC0krHwV6CwOkqqWBYgVWF5whCRwr1BMgQ8ECAYCBp8kFwIwCAQIvN")) diff --git a/apps/animclk/app.js b/apps/animclk/app.js new file mode 100644 index 000000000..ced5372a0 --- /dev/null +++ b/apps/animclk/app.js @@ -0,0 +1,106 @@ +var pal = new Uint16Array(E.toArrayBuffer(E.toString(require("Storage").read("animclk.pal")))); +var img1 = require("Storage").read("animclk.pixels1"); +var img1height = img1.length/240; +var img2 = require("Storage").read("animclk.pixels2"); +var img2height = img2.length/240; +var cycle = [ + {reverse:0,rate:1,low:32,high:47}, + {reverse:0,rate:3,low:48,high:63}, + {reverse:0,rate:3,low:64,high:79}, + {reverse:0,rate:2,low:80,high:95}, + {reverse:0,rate:1,low:96,high:103}, + {reverse:0,rate:3,low:128,high:143}, + {reverse:0,rate:2,low:22,high:31} +]; +var is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; +var IX = 80, IY = 10, IBPP = 1; +var IW = 174, IH = 45, OY = 24; +var inf = {align:0}; +var bgoptions; + +require("Font7x11Numeric7Seg").add(Graphics); +var cg = Graphics.createArrayBuffer(IW,IH,IBPP,{msb:true}); +var cgimg = {width:IW,height:IH,bpp:IBPP,transparent:0,buffer:cg.buffer}; +var locale = require("locale"); +var lastTime = ""; + +function drawClock() { + var t = new Date(); + var hours = t.getHours(); + var meridian = ""; + if (is12Hour) { + meridian = (hours < 12) ? "AM" : "PM"; + hours = ((hours + 11) % 12) + 1; + } + // draw time + cg.clear(1); + cg.setColor(1); + var x = 74 + 32 * inf.align; + cg.setFont("7x11Numeric7Seg",3); + cg.setFontAlign(1,-1); + cg.drawString(hours, x, 0); + x+=2; + if (t.getSeconds() & 1) + cg.fillRect(x, 10, x+2, 10+2).fillRect(x, 20, x+2, 20+2); + x+=6; + cg.setFontAlign(-1,-1); + cg.drawString(("0"+t.getMinutes()).substr(-2), x, 0); + x+=44; + cg.setFont("7x11Numeric7Seg",1); + cg.drawString(("0"+t.getSeconds()).substr(-2), x, 20); + cg.setFont("6x8",1); + cg.drawString(meridian, x+2, 0); + let date = locale.date(t); + if (cg.stringWidth(date) < IW-64) { + cg.setFontAlign(0, -1); + cg.drawString(date,IW/2+32*inf.align,IH-8); + } else { + cg.setFontAlign(inf.align, -1); + cg.drawString(date,IW*(inf.align+1)/2,IH-8); + } +} + +function draw() { + var t = (new Date()).toString(); + if (t!=lastTime) { + lastTime = t; + drawClock(); + } + // color cycling + cycle.forEach(c=>{ + var p = pal.slice(c.low,c.high); + pal[c.low] = pal[c.high]; + pal.set(p,c.low+1); + }); + // draw image + g.setColor(-1); + // draw just the clock part overlaid (to avoid flicker) + g.drawImages([{x:0,y:OY,image:{width:240,height:img1height,bpp:8,palette:pal,buffer:img1}}, + {image:cgimg,x:IX,y:IY+OY}], + {x:0,y:OY,width:239,height:img1height}); + // now draw the image on its own below - this is faster + g.drawImage({width:240,height:img2height,bpp:8,palette:pal,buffer:img2},0,OY+img1height); +} + +if (g.drawImages) { + // draw clock itself and do it every second + draw(); + var secondInterval = setInterval(draw,100); + // load widgets + Bangle.loadWidgets(); + Bangle.drawWidgets(); + // Stop when LCD goes off + Bangle.on('lcdPower',on=>{ + if (secondInterval) clearInterval(secondInterval); + secondInterval = undefined; + if (on) { + secondInterval = setInterval(draw,100); + lastTime=""; + draw(); + } + }); +} else { + E.showMessage("Please update\nBangle.js firmware\nto use this clock","animclk"); +} +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); diff --git a/apps/animclk/app.png b/apps/animclk/app.png new file mode 100644 index 000000000..63eac03e5 Binary files /dev/null and b/apps/animclk/app.png differ diff --git a/apps/animclk/create_images.js b/apps/animclk/create_images.js new file mode 100644 index 000000000..8436d99b3 --- /dev/null +++ b/apps/animclk/create_images.js @@ -0,0 +1,57 @@ +/* Creates an image and palette based off of +an image from http://www.effectgames.com/demos/canvascycle/ + +You just need to open devtools and find the `CanvasCycle.processImage` +call, then create a file for it. eg. + +http://www.effectgames.com/demos/canvascycle/image.php?file=V29&callback=CanvasCycle.processImage + +Finally cycles just needs adding +*/ +var CanvasCycle = { + processImage : function(info) { + const IMG1_HEIGHT = 55; + const IMG2_HEIGHT = 240-(24+55); + var img1 = Buffer.alloc(240*IMG1_HEIGHT); + var img2 = Buffer.alloc(240*IMG2_HEIGHT); + var n=0; + /* img.writeUInt8(240, n++); + img.writeUInt8(240, n++); + img.writeUInt8(8, n++);*/ + var pal = Buffer.alloc(256*2); + + for (var i=0;i>3); + pal.writeUInt16LE(p, i*2); + } + + function getPixel(x,y) { + return info.pixels[(x+640-240)+((y+480-240)*640)]; + } + + n = 0; + for (var y=0;y { - let m = moonIndexPageMenu(gps); + let m = moonIndexPageMenu(gps); }, BTN3, {repeat: false, edge: "falling"}); } @@ -222,61 +232,61 @@ function drawSunShowPage(gps, key, date) { drawPoint(azimuthDegrees, 8, {r: 1, g: 1, b: 0}); m = setWatch(() => { - m = sunIndexPageMenu(gps); + m = sunIndexPageMenu(gps); }, BTN3, {repeat: false, edge: "falling"}); return null; } function sunIndexPageMenu(gps) { - const sunTimes = SunCalc.getTimes(new Date(), gps.lat, gps.lon); + const sunTimes = SunCalc.getTimes(new Date(), gps.lat, gps.lon); - const sunMenu = { - "": { - "title": "-- Sun --", - }, - "Current Pos": () => { - m = E.showMenu(); - drawSunShowPage(gps, "Current Pos", new Date()); - }, + const sunMenu = { + "": { + "title": "-- Sun --", + }, + "Current Pos": () => { + m = E.showMenu(); + drawSunShowPage(gps, "Current Pos", new Date()); + }, + }; + + Object.keys(sunTimes).sort().reduce((menu, key) => { + const title = titlizeKey(key); + menu[title] = () => { + m = E.showMenu(); + drawSunShowPage(gps, key, sunTimes[key]); }; + return menu; + }, sunMenu); - Object.keys(sunTimes).sort().reduce((menu, key) => { - const title = titlizeKey(key); - menu[title] = () => { - m = E.showMenu(); - drawSunShowPage(gps, key, sunTimes[key]); - }; - return menu; - }, sunMenu); + sunMenu["< Back"] = () => m = indexPageMenu(gps); - sunMenu["< Back"] = () => m = indexPageMenu(gps); - - return E.showMenu(sunMenu); + return E.showMenu(sunMenu); } function moonIndexPageMenu(gps) { - const moonMenu = { - "": { - "title": "-- Moon --", - }, - "Times": () => { - m = E.showMenu(); - drawMoonTimesPage(gps, "Times"); - }, - "Position": () => { - m = E.showMenu(); - drawMoonPositionPage(gps, "Position"); - }, - "Illumination": () => { - m = E.showMenu(); - drawMoonIlluminationPage(gps, "Illumination"); - }, - "< Back": () => m = indexPageMenu(gps), - }; + const moonMenu = { + "": { + "title": "-- Moon --", + }, + "Times": () => { + m = E.showMenu(); + drawMoonTimesPage(gps, "Times"); + }, + "Position": () => { + m = E.showMenu(); + drawMoonPositionPage(gps, "Position"); + }, + "Illumination": () => { + m = E.showMenu(); + drawMoonIlluminationPage(gps, "Illumination"); + }, + "< Back": () => m = indexPageMenu(gps), + }; - return E.showMenu(moonMenu); + return E.showMenu(moonMenu); } function indexPageMenu(gps) { @@ -296,52 +306,82 @@ function indexPageMenu(gps) { return E.showMenu(menu); } +function getCenterStringX(str) { + return (g.getWidth() - g.stringWidth(str)) / 2; +} + /** * GPS wait page, shows GPS locating animation until it gets a lock, then moves to the Sun page */ function drawGPSWaitPage() { - const img = require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AW43GF1wwsFwYwqFwowoFw4wmFxIwdE5YAPF/4vM5nN6YAE5vMF8YtHGIgvhFpQxKF7AuOGA4vXFyAwGF63MFyIABF6xeWMC4UDLwvNGpAJG5gwSdhIIDRBLyWCIgcJHAgJJDoouQF4vMQoICBBJoeGFx6GGACIfHL6YvaX6gvZeCIdFc4gAFXogvGFxgwFDwovQCAguOGAnMMBxeG5guTGAggGGAwNKFySREcA3N5vM5gDBdpQvXEY4AKXqovGGCKbFF7AwPZQwvZGJgtGF7vGdQItG5gSIF7gASF/44WEzgwRF0wwHF1AwFF1QwDF1gvwAH4A/AFAA==")) - - g.clear(); - g.drawImage(img, 100, 50); - g.setFont("6x8", 1); - g.drawString("Astrocalc v0.01", 80, 105); - g.drawString("Locating GPS", 85, 140); - g.drawString("Please wait...", 80, 155); - g.flip(); + const img = require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AW43GF1wwsFwYwqFwowoFw4wmFxIwdE5YAPF/4vM5nN6YAE5vMF8YtHGIgvhFpQxKF7AuOGA4vXFyAwGF63MFyIABF6xeWMC4UDLwvNGpAJG5gwSdhIIDRBLyWCIgcJHAgJJDoouQF4vMQoICBBJoeGFx6GGACIfHL6YvaX6gvZeCIdFc4gAFXogvGFxgwFDwovQCAguOGAnMMBxeG5guTGAggGGAwNKFySREcA3N5vM5gDBdpQvXEY4AKXqovGGCKbFF7AwPZQwvZGJgtGF7vGdQItG5gSIF7gASF/44WEzgwRF0wwHF1AwFF1QwDF1gvwAH4A/AFAA==")); + const str1 = "Astrocalc v0.02"; + const str2 = "Locating GPS"; + const str3 = "Please wait..."; - const DEBUG = false; - if (DEBUG) { - const gps = { - "lat": 56.45783133333, - "lon": -3.02188583333, - "alt": 75.3, - "speed": 0.070376, - "course": NaN, - "time":new Date(), - "satellites": 4, - "fix": 1 - }; + g.clear(); + g.drawImage(img, 100, 50); + g.setFont("6x8", 1); + g.drawString(str1, getCenterStringX(str1), 105); + g.drawString(str2, getCenterStringX(str2), 140); + g.drawString(str3, getCenterStringX(str3), 155); - m = indexPageMenu(gps); + if (lastGPS) { + lastGPS = JSON.parse(lastGPS); + lastGPS.time = new Date(); - return; - } + const str4 = "Press Button 3 to use last GPS"; + g.setColor("#d32e29"); + g.fillRect(0, 190, g.getWidth(), 215); + g.setColor("#ffffff"); + g.drawString(str4, getCenterStringX(str4), 200); - Bangle.on('GPS', (gps) => { - if (gps.fix === 0) return; + setWatch(() => { + clearWatch(); + Bangle.setGPSPower(0); + m = indexPageMenu(lastGPS); + }, BTN3, {repeat: false}); + } - Bangle.setGPSPower(0); - Bangle.buzz(); - Bangle.setLCDPower(true); + g.flip(); - m = indexPageMenu(gps); - }); + const DEBUG = false; + if (DEBUG) { + clearWatch(); + + const gps = { + "lat": 56.45783133333, + "lon": -3.02188583333, + "alt": 75.3, + "speed": 0.070376, + "course": NaN, + "time":new Date(), + "satellites": 4, + "fix": 1 + }; + + m = indexPageMenu(gps); + + return; + } + + Bangle.on('GPS', (gps) => { + if (gps.fix === 0) return; + clearWatch(); + + if (isNaN(gps.course)) gps.course = 0; + require("Storage").writeJSON(LAST_GPS_FILE, JSON.stringify(gps)); + Bangle.setGPSPower(0); + Bangle.buzz(); + Bangle.setLCDPower(true); + + m = indexPageMenu(gps); + }); } function init() { - Bangle.setGPSPower(1); - drawGPSWaitPage(); + Bangle.setGPSPower(1); + drawGPSWaitPage(); } let m; diff --git a/apps/astrocalc/suncalc.js b/apps/astrocalc/suncalc.js index 6ef5aa2d0..e2beaedca 100644 --- a/apps/astrocalc/suncalc.js +++ b/apps/astrocalc/suncalc.js @@ -6,9 +6,9 @@ (function () { 'use strict'; -// shortcuts for easier to read formulas + // shortcuts for easier to read formulas -var PI = Math.PI, + var PI = Math.PI, sin = Math.sin, cos = Math.cos, tan = Math.tan, @@ -17,219 +17,219 @@ var PI = Math.PI, acos = Math.acos, rad = PI / 180; -// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas + // sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas -// date/time constants and conversions + // date/time constants and conversions -var dayMs = 1000 * 60 * 60 * 24, + var dayMs = 1000 * 60 * 60 * 24, J1970 = 2440588, J2000 = 2451545; -function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; } -function fromJulian(j) { return (j + 0.5 - J1970) * dayMs; } -function toDays(date) { return toJulian(date) - J2000; } + function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; } + function fromJulian(j) { return (j + 0.5 - J1970) * dayMs; } + function toDays(date) { return toJulian(date) - J2000; } -// general calculations for position + // general calculations for position -var e = rad * 23.4397; // obliquity of the Earth + var e = rad * 23.4397; // obliquity of the Earth -function rightAscension(l, b) { return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l)); } -function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); } + function rightAscension(l, b) { return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l)); } + function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); } -function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)); } -function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); } + function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)); } + function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); } -function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; } + function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; } -function astroRefraction(h) { + function astroRefraction(h) { if (h < 0) // the following formula works for positive altitudes only. - h = 0; // if h = -0.08901179 a div/0 would occur. + h = 0; // if h = -0.08901179 a div/0 would occur. // formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. // 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad: return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179)); -} + } -// general sun calculations + // general sun calculations -function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); } + function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); } -function eclipticLongitude(M) { + function eclipticLongitude(M) { var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center - P = rad * 102.9372; // perihelion of the Earth + P = rad * 102.9372; // perihelion of the Earth return M + C + P + PI; -} + } -function sunCoords(d) { + function sunCoords(d) { var M = solarMeanAnomaly(d), - L = eclipticLongitude(M); + L = eclipticLongitude(M); return { - dec: declination(L, 0), - ra: rightAscension(L, 0) + dec: declination(L, 0), + ra: rightAscension(L, 0) }; -} + } -var SunCalc = {}; + var SunCalc = {}; -// calculates sun position for a given date and latitude/longitude + // calculates sun position for a given date and latitude/longitude -SunCalc.getPosition = function (date, lat, lng) { + SunCalc.getPosition = function (date, lat, lng) { var lw = rad * -lng, - phi = rad * lat, - d = toDays(date), + phi = rad * lat, + d = toDays(date), - c = sunCoords(d), - H = siderealTime(d, lw) - c.ra; + c = sunCoords(d), + H = siderealTime(d, lw) - c.ra; return { - azimuth: azimuth(H, phi, c.dec), - altitude: altitude(H, phi, c.dec) + azimuth: azimuth(H, phi, c.dec), + altitude: altitude(H, phi, c.dec) }; -}; + }; -// sun times configuration (angle, morning name, evening name) + // sun times configuration (angle, morning name, evening name) -var times = SunCalc.times = [ + var times = SunCalc.times = [ [-0.833, 'sunrise', 'sunset' ], [ -0.3, 'sunriseEnd', 'sunsetStart' ], [ -6, 'dawn', 'dusk' ], [ -12, 'nauticalDawn', 'nauticalDusk'], [ -18, 'nightEnd', 'night' ], [ 6, 'goldenHourEnd', 'goldenHour' ] -]; + ]; -// adds a custom time to the times config + // adds a custom time to the times config -SunCalc.addTime = function (angle, riseName, setName) { + SunCalc.addTime = function (angle, riseName, setName) { times.push([angle, riseName, setName]); -}; + }; -// calculations for sun times + // calculations for sun times -var J0 = 0.0009; + var J0 = 0.0009; -function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); } + function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); } -function approxTransit(Ht, lw, n) { return J0 + (Ht + lw) / (2 * PI) + n; } -function solarTransitJ(ds, M, L) { return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); } + function approxTransit(Ht, lw, n) { return J0 + (Ht + lw) / (2 * PI) + n; } + function solarTransitJ(ds, M, L) { return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); } -function hourAngle(h, phi, d) { return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d))); } -function observerAngle(height) { return -2.076 * Math.sqrt(height) / 60; } + function hourAngle(h, phi, d) { return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d))); } + function observerAngle(height) { return -2.076 * Math.sqrt(height) / 60; } -// returns set time for the given sun altitude -function getSetJ(h, lw, phi, dec, n, M, L) { + // returns set time for the given sun altitude + function getSetJ(h, lw, phi, dec, n, M, L) { var w = hourAngle(h, phi, dec), - a = approxTransit(w, lw, n); + a = approxTransit(w, lw, n); return solarTransitJ(a, M, L); -} + } -// calculates sun times for a given date, latitude/longitude, and, optionally, -// the observer height (in meters) relative to the horizon + // calculates sun times for a given date, latitude/longitude, and, optionally, + // the observer height (in meters) relative to the horizon -SunCalc.getTimes = function (date, lat, lng, height) { + SunCalc.getTimes = function (date, lat, lng, height) { height = height || 0; var lw = rad * -lng, - phi = rad * lat, + phi = rad * lat, - dh = observerAngle(height), + dh = observerAngle(height), - d = toDays(date), - n = julianCycle(d, lw), - ds = approxTransit(0, lw, n), + d = toDays(date), + n = julianCycle(d, lw), + ds = approxTransit(0, lw, n), - M = solarMeanAnomaly(ds), - L = eclipticLongitude(M), - dec = declination(L, 0), + M = solarMeanAnomaly(ds), + L = eclipticLongitude(M), + dec = declination(L, 0), - Jnoon = solarTransitJ(ds, M, L), + Jnoon = solarTransitJ(ds, M, L), - i, len, time, h0, Jset, Jrise; + i, len, time, h0, Jset, Jrise; var result = { - solarNoon: new Date(fromJulian(Jnoon)), - nadir: new Date(fromJulian(Jnoon - 0.5)) + solarNoon: new Date(fromJulian(Jnoon)), + nadir: new Date(fromJulian(Jnoon - 0.5)) }; for (i = 0, len = times.length; i < len; i += 1) { - time = times[i]; - h0 = (time[0] + dh) * rad; + time = times[i]; + h0 = (time[0] + dh) * rad; - Jset = getSetJ(h0, lw, phi, dec, n, M, L); - Jrise = Jnoon - (Jset - Jnoon); + Jset = getSetJ(h0, lw, phi, dec, n, M, L); + Jrise = Jnoon - (Jset - Jnoon); - result[time[1]] = new Date(fromJulian(Jrise) - (dayMs / 2)); - result[time[2]] = new Date(fromJulian(Jset) + (dayMs / 2)); + result[time[1]] = new Date(fromJulian(Jrise) - (dayMs / 2)); + result[time[2]] = new Date(fromJulian(Jset) + (dayMs / 2)); } return result; -}; + }; -// moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas + // moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas -function moonCoords(d) { // geocentric ecliptic coordinates of the moon + function moonCoords(d) { // geocentric ecliptic coordinates of the moon var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude - M = rad * (134.963 + 13.064993 * d), // mean anomaly - F = rad * (93.272 + 13.229350 * d), // mean distance + M = rad * (134.963 + 13.064993 * d), // mean anomaly + F = rad * (93.272 + 13.229350 * d), // mean distance - l = L + rad * 6.289 * sin(M), // longitude - b = rad * 5.128 * sin(F), // latitude - dt = 385001 - 20905 * cos(M); // distance to the moon in km + l = L + rad * 6.289 * sin(M), // longitude + b = rad * 5.128 * sin(F), // latitude + dt = 385001 - 20905 * cos(M); // distance to the moon in km return { - ra: rightAscension(l, b), - dec: declination(l, b), - dist: dt + ra: rightAscension(l, b), + dec: declination(l, b), + dist: dt }; -} + } -SunCalc.getMoonPosition = function (date, lat, lng) { + SunCalc.getMoonPosition = function (date, lat, lng) { var lw = rad * -lng, - phi = rad * lat, - d = toDays(date), + phi = rad * lat, + d = toDays(date), - c = moonCoords(d), - H = siderealTime(d, lw) - c.ra, - h = altitude(H, phi, c.dec), - // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. - pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H)); + c = moonCoords(d), + H = siderealTime(d, lw) - c.ra, + h = altitude(H, phi, c.dec), + // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. + pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H)); h = h + astroRefraction(h); // altitude correction for refraction return { - azimuth: azimuth(H, phi, c.dec), - altitude: h, - distance: c.dist, - parallacticAngle: pa + azimuth: azimuth(H, phi, c.dec), + altitude: h, + distance: c.dist, + parallacticAngle: pa }; -}; + }; -// calculations for illumination parameters of the moon, -// based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and -// Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. + // calculations for illumination parameters of the moon, + // based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and + // Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. -// Function updated from gist: https://gist.github.com/endel/dfe6bb2fbe679781948c + // Function updated from gist: https://gist.github.com/endel/dfe6bb2fbe679781948c -SunCalc.getMoonIllumination = function (date) { + SunCalc.getMoonIllumination = function (date) { let month = date.getMonth(); let year = date.getFullYear(); let day = date.getDate(); @@ -256,57 +256,57 @@ SunCalc.getMoonIllumination = function (date) { if (b >= 8) b = 0; // 0 and 8 are the same so turn 8 into 0 return {phase: b}; -}; + }; -function hoursLater(date, h) { + function hoursLater(date, h) { return new Date(date.valueOf() + h * dayMs / 24); -} + } -// calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article + // calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article -SunCalc.getMoonTimes = function (date, lat, lng, inUTC) { + SunCalc.getMoonTimes = function (date, lat, lng, inUTC) { var t = date; if (inUTC) t.setUTCHours(0, 0, 0, 0); else t.setHours(0, 0, 0, 0); var hc = 0.133 * rad, - h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc, - h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx; + h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc, + h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx; // go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set) for (var i = 1; i <= 24; i += 2) { - h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc; - h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc; + h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc; + h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc; - a = (h0 + h2) / 2 - h1; - b = (h2 - h0) / 2; - xe = -b / (2 * a); - ye = (a * xe + b) * xe + h1; - d = b * b - 4 * a * h1; - roots = 0; + a = (h0 + h2) / 2 - h1; + b = (h2 - h0) / 2; + xe = -b / (2 * a); + ye = (a * xe + b) * xe + h1; + d = b * b - 4 * a * h1; + roots = 0; - if (d >= 0) { - dx = Math.sqrt(d) / (Math.abs(a) * 2); - x1 = xe - dx; - x2 = xe + dx; - if (Math.abs(x1) <= 1) roots++; - if (Math.abs(x2) <= 1) roots++; - if (x1 < -1) x1 = x2; - } + if (d >= 0) { + dx = Math.sqrt(d) / (Math.abs(a) * 2); + x1 = xe - dx; + x2 = xe + dx; + if (Math.abs(x1) <= 1) roots++; + if (Math.abs(x2) <= 1) roots++; + if (x1 < -1) x1 = x2; + } - if (roots === 1) { - if (h0 < 0) rise = i + x1; - else set = i + x1; + if (roots === 1) { + if (h0 < 0) rise = i + x1; + else set = i + x1; - } else if (roots === 2) { - rise = i + (ye < 0 ? x2 : x1); - set = i + (ye < 0 ? x1 : x2); - } + } else if (roots === 2) { + rise = i + (ye < 0 ? x2 : x1); + set = i + (ye < 0 ? x1 : x2); + } - if (rise && set) break; + if (rise && set) break; - h0 = h2; + h0 = h2; } var result = {}; @@ -317,12 +317,12 @@ SunCalc.getMoonTimes = function (date, lat, lng, inUTC) { if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true; return result; -}; + }; -// export as Node module / AMD module / browser variable -if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = SunCalc; -else if (typeof define === 'function' && define.amd) define(SunCalc); -else global.SunCalc = SunCalc; + // export as Node module / AMD module / browser variable + if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = SunCalc; + else if (typeof define === 'function' && define.amd) define(SunCalc); + else global.SunCalc = SunCalc; }()); diff --git a/apps/astroid/ChangeLog b/apps/astroid/ChangeLog new file mode 100644 index 000000000..42c1df403 --- /dev/null +++ b/apps/astroid/ChangeLog @@ -0,0 +1 @@ +0.02: Add "ram" keyword to allow 2v06 Espruino builds to cache function that needs to be fast diff --git a/apps/astroid/asteroids.js b/apps/astroid/asteroids.js index cb44db904..da4dc017e 100644 --- a/apps/astroid/asteroids.js +++ b/apps/astroid/asteroids.js @@ -59,6 +59,7 @@ function gameStart() { function onFrame() { + "ram" var t = getTime(); var d = (lastFrame===undefined)?0:(t-lastFrame)*20; lastFrame = t; diff --git a/apps/ballmaze/ChangeLog b/apps/ballmaze/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/ballmaze/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/ballmaze/README.md b/apps/ballmaze/README.md new file mode 100644 index 000000000..22a295686 --- /dev/null +++ b/apps/ballmaze/README.md @@ -0,0 +1,15 @@ +# Ball Maze + +Navigate a ball through a maze by tilting your watch. + +![Screenshot](size_select.png) +![Screenshot](maze.png) + +## Usage + +Select a maze size to begin the game. +Tilt your watch to steer the ball towards the target and advance to the next level. + +## Creator + +Richard de Boer diff --git a/apps/ballmaze/app.js b/apps/ballmaze/app.js new file mode 100644 index 000000000..3e26277b7 --- /dev/null +++ b/apps/ballmaze/app.js @@ -0,0 +1,552 @@ +(() => { + let intervalID; + let settings = require("Storage").readJSON("ballmaze.json",true) || {}; + + // density, elasticity of bounces, "drag coefficient" + const rho = 100, e = 0.3, C = 0.01; + // screen width & height in pixels + const sW = 240, sH = 160; + // gravity constant (lowercase was already taken) + const G = 9.80665; + + // wall bit flags + const TOP = 1<<0, LEFT = 1<<1, BOTTOM = 1<<2, RIGHT = 1<<3, + LINKED = 1<<4; // used in maze generation + + // The play area is 240x160, sizes are the ball radius, so we can use common + // denominators of 120x80 to get square rooms + // Reverse the order to show the easiest on top of the menu + const sizes = [1, 2, 4, 5, 8, 10, 16, 20, 40].reverse(), + // even size 1 actually works, but larger mazes take forever to generate + minSize = 4, defaultSize = 10; + const sizeNames = { + 1: "Insane", 2: "Gigantic", 4: "Enormous", 5: "Huge", 8: "Large", + 10: "Medium", 16: "Small", 20: "Tiny", 40: "Trivial", + }; + + /** + * Draw something to all screen buffers + * @param draw {function} Callback which performs the drawing + */ + function drawAll(draw) { + draw(); + g.flip(); + draw(); + g.flip(); + } + + /** + * Clear all buffers + */ + function clearAll() { + drawAll(() => g.clear()); + } + + // use unbuffered graphics for UI stuff + function showMessage(message, title) { + Bangle.setLCDMode(); + return E.showMessage(message, title); + } + + function showPrompt(prompt, options) { + Bangle.setLCDMode(); + return E.showPrompt(prompt, options); + } + + function showMenu(menu) { + Bangle.setLCDMode(); + return E.showMenu(menu); + } + + const sign = (n) => n<0?-1:1; // we don't really care about zero + + /** + * Play the game, using a ball with radius size + * @param size {number} + */ + function playMaze(size) { + const r = size; + // ball mass, weight, "drag" + // Yes, larger maze = larger ball = heavier ball + // (atm our physics is so oversimplified that mass cancels out though) + const m = rho*(r*r*r), w = G*m, d = C*w; + + // number of columns/rows + const cols = Math.round(sW/(r*2.5)), + rows = Math.round(sH/(r*2.5)); + // width & height of one column/row in pixels + const cW = sW/cols, rH = sH/rows; + + // list of rooms, every room can have one or more wall bits set + // actual layout: 0 1 2 + // 3 4 5 + // this means that for room with index "i": (except edge cases!) + // i-1 = room to the left + // i+1 = room to the right + // i-cols = room above + // i+cols = room below + let rooms = new Uint8Array(rows*cols); + // shortest route from start to finish + let route; + + let x, y, // current position + px, py, ppx, ppy, // previous positions (for erasing old image) + vx, vy; // velocity + + function start() { + // start in top left corner + x = cW/2; + y = rH/2; + vx = vy = 0; + ppx = px = x; + ppy = py = y; + + generateMaze(); // this shows unbuffered progress messages + if (settings.cheat && r>1) findRoute(); // not enough memory for r==1 :-( + + Bangle.setLCDMode("doublebuffered"); + clearAll(); + drawAll(drawMaze); + intervalID = setInterval(tick, 100); + } + + // Position conversions + // index: index of room in rooms[] + // rowcol: position measured in roomsizes + // xy: position measured in pixels + /** + * Index from RowCol + * @param row {number} + * @param col {number} + * @returns {number} rooms[] index + */ + function iFromRC(row, col) { + return row*cols+col; + } + + /** + * RowCol from index + * @param index {number} + * @returns {(number)[]} [row,column] + */ + function rcFromI(index) { + return [ + Math.floor(index/cols), + index%cols, + ]; + } + + /** + * RowCol from Xy + * @param x {number} + * @param y {number} + * @returns {(number)[]} [row,column] + */ + function rcFromXy(x, y) { + return [ + Math.floor(y/sH*rows), + Math.floor(x/sW*cols), + ]; + } + + /** + * Link another room up + * @param index {number} Dig from already linked room with this index + * @param dir {number} in this direction + * @return {number} index of room we just linked up + */ + function dig(index, dir) { + rooms[index] &= ~dir; + let neighbour; + switch(dir) { + case LEFT: + neighbour = index-1; + rooms[neighbour] &= ~RIGHT; + break; + case RIGHT: + neighbour = index+1; + rooms[neighbour] &= ~LEFT; + break; + case TOP: + neighbour = index-cols; + rooms[neighbour] &= ~BOTTOM; + break; + case BOTTOM: + neighbour = index+cols; + rooms[neighbour] &= ~TOP; + break; + } + rooms[neighbour] |= LINKED; + return neighbour; + } + + /** + * Generate the maze + */ + function generateMaze() { + // Maze generation basically works like this: + // 1. Start with all rooms set to completely walled off and "unlinked" + // 2. Then mark a room as "linked", and add it to the "to do" list + // 3. When the "to do" list is empty, we're done + // 4. pick a random room from the list + // 5. if all adjacent rooms are linked -> remove room from list, goto 3 + // 6. pick a random unlinked adjacent room + // 7. remove the walls between the rooms + // 8. mark the adjacent room as linked and add it to the "to do" list + // 9. go to 4 + let pdotnum = 0; + const title = "Please wait", + message = "Generating maze\n", + showProgress = (done, total) => { + const dotnum = Math.floor(done/total*10); + if (dotnum>pdotnum) { + const dots = ".".repeat(dotnum)+" ".repeat(10-dotnum); + showMessage(message+dots, title); + pdotnum = dotnum; + } + }; + showProgress(0, 100); + // start with all rooms completely walled off + rooms.fill(TOP|LEFT|BOTTOM|RIGHT); + const + // is room at row,col already linked? + linked = (row, col) => !!(rooms[iFromRC(row, col)]&LINKED), + // pick random array element + pickRandom = (arr) => arr[Math.floor(Math.random()*arr.length)]; + // starting with top-right room seems to generate more interesting mazes + rooms[cols] |= LINKED; + let todo = [cols], done = 1; + while(todo.length) { + const index = pickRandom(todo); + const rc = rcFromI(index), + row = rc[0], col = rc[1]; + let sides = []; + if ((col>0) && !linked(row, col-1)) sides.push(LEFT); + if ((col0) && !linked(row-1, col)) sides.push(TOP); + if ((row0 && !(walls&LEFT) && dist[i-1]>d+1) { + dist[i-1] = d+1; + todo.push(i-1); + } + if (row>0 && !(walls&TOP) && dist[i-cols]>d+1) { + dist[i-cols] = d+1; + todo.push(i-cols); + } + if (cold+1) { + dist[i+1] = d+1; + todo.push(i+1); + } + if (rowd+1) { + dist[i+cols] = d+1; + todo.push(i+cols); + } + } + + route = [rooms.length-1]; + while(true) { + const i = route[0], d = dist[i], walls = rooms[i], + rc = rcFromI(i), + row = rc[0], col = rc[1]; + if (i===0) { break; } + if (col0 && !(walls&TOP) && dist[i-cols]0 && !(walls&LEFT) && dist[i-1] { + const rc = rcFromI(i), + row = rc[0], col = rc[1], + x = (col+0.5)*cW, y = (row+0.5)*rH; + g.lineTo(x, y); + }); + } + + /** + * Move the ball + */ + function move() { + const a = Bangle.getAccel(); + const fx = (-a.x*w)-(sign(vx)*d*a.z), fy = (-a.y*w)-(sign(vy)*d*a.z); + vx += fx/m; + vy += fy/m; + const s = Math.ceil(Math.max(Math.abs(vx), Math.abs(vy))); + for(let n = s; n>0; n--) { + x += vx/s; + y += vy/s; + bounce(); + } + if (x>sW-cW && y>sH-rH) win(); + } + + /** + * Check whether we hit any walls, and if so: Bounce. + * + * Bounce = reverse velocity in bounce direction, multiply with elasticity + * Also apply drag in perpendicular direction ("friction with the wall") + */ + function bounce() { + const row = Math.floor(y/sH*rows), col = Math.floor(x/sW*cols), + i = row*cols+col, walls = rooms[i]; + const left = col*cW, + right = (col+1)*cW, + top = row*rH, + bottom = (row+1)*rH; + let bounced = false; + if (vx<0) { + if ((walls&LEFT) && x<=left+r) { + x += (1+e)*(left+r-x); + const fy = sign(vy)*d*Math.abs(vx); + vy -= fy/m; + vx = -vx*e; + bounced = true; + } + } else { + if ((walls&RIGHT) && x>=right-r) { + x -= (1+e)*(x+r-right); + const fy = sign(vy)*d*Math.abs(vx); + vy -= fy/m; + vx = -vx*e; + bounced = true; + } + } + if (vy<0) { + if ((walls&TOP) && y<=top+r) { + y += (1+e)*(top+r-y); + const fx = sign(vx)*d*Math.abs(vy); + vx -= fx/m; + vy = -vy*e; + bounced = true; + } + } else { + if ((walls&BOTTOM) && y>=bottom-r) { + y -= (1+e)*(y+r-bottom); + const fx = sign(vx)*d*Math.abs(vy); + vx -= fx/m; + vy = -vy*e; + bounced = true; + } + } + if (bounced) return; + let cx, cy; + if ((rooms[i-1]&TOP) || rooms[i-cols]&LEFT) { + if ((x-left)*(x-left)+(y-top)*(y-top)<=r*r) { + cx = left; + cy = top; + } + } + else if ((rooms[i-1]&BOTTOM) || rooms[i+cols]&LEFT) { + if ((x-left)*(x-left)+(bottom-y)*(bottom-y)<=r*r) { + cx = left; + cy = bottom; + } + } + else if ((rooms[i+1]&TOP) || rooms[i-cols]&RIGHT) { + if ((right-x)*(right-x)+(y-top)*(y-top)<=r*r) { + cx = right; + cy = top; + } + } + else if ((rooms[i+1]&BOTTOM) || rooms[i+cols]&RIGHT) { + if ((right-x)*(right-x)+(bottom-y)*(bottom-y)<=r*r) { + cx = right; + cy = bottom; + } + } + if (!cx) return; + let nx = x-cx, ny = y-cy; + const l = Math.sqrt(nx*nx+ny*ny); + nx /= l; + ny /= l; + const p = vx*nx+vy*ny; + vx -= 2*p*nx*e; + vy -= 2*p*ny*e; + } + + /** + * You reached the bottom-right corner, you win! + */ + function win() { + clearInterval(intervalID); + Bangle.buzz().then(askAgain); + } + + /** + * You solved the maze, try the next one? + */ + function askAgain() { + const nextLevel = (size>minSize)?"next level":"again"; + const nextSize = (size>minSize)?sizes[sizes.indexOf(size)+1]:size; + showPrompt(`Well done!\n\nPlay ${nextLevel}?`, + {"title": "Congratulations!"}) + .then(function(again) { + if (again) { + playMaze(nextSize); + } else { + startGame(); + } + }); + } + + function tick() { + ppx = px; + ppy = py; + px = x; + py = y; + move(); + drawUpdate(); + } + + start(); + } + + /** + * Ask player what size maze they would like to play + */ + function startGame() { + let menu = { + "": { + title: "Select Maze Size", + selected: sizes.indexOf(settings.size || defaultSize), + }, + }; + sizes.filter(s => s>=minSize).forEach(size => { + let name = sizeNames[size]; + if (size { + // remember chosen size + settings.size = size; + require("Storage").write("ballmaze.json", settings); + playMaze(size); + }; + }); + menu["< Exit"] = () => load(); + showMenu(menu); + } + + startGame(); +})(); diff --git a/apps/ballmaze/icon.js b/apps/ballmaze/icon.js new file mode 100644 index 000000000..10b5a502e --- /dev/null +++ b/apps/ballmaze/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AH4AU9wAOCw0OC5/gFyowHC+Hs5gACC7HhiMRjwXSCoIADC5wCB4MSkIXDGIoXKiUikQwJC5PhCwIXFGAgXJFwRHEGAnOC5HhC5IwC5gXJIw4XF4AXKFwwXEGAoXCiKlFMAzNCgDpDC4QAKcgZJBC6wADF6kAhgXP5xfEC58SC4iNCC4nhC5McC4S/DC6a9DC4IACC5MhC4XOC5HuLxPMC4PuC5IwHkUeC44ABA4IACFw5cBC5owEkUhjwXPGAyMCC5wxDLgIACC54ADC94AGC7sOCx/gC4owQCwwA/AH4AMA")) diff --git a/apps/ballmaze/icon.png b/apps/ballmaze/icon.png new file mode 100644 index 000000000..44697db4b Binary files /dev/null and b/apps/ballmaze/icon.png differ diff --git a/apps/ballmaze/maze.png b/apps/ballmaze/maze.png new file mode 100644 index 000000000..7bda56d9b Binary files /dev/null and b/apps/ballmaze/maze.png differ diff --git a/apps/ballmaze/size_select.png b/apps/ballmaze/size_select.png new file mode 100644 index 000000000..cac278820 Binary files /dev/null and b/apps/ballmaze/size_select.png differ diff --git a/apps/banglerun/.gitignore b/apps/banglerun/.gitignore new file mode 100644 index 000000000..c2658d7d1 --- /dev/null +++ b/apps/banglerun/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/apps/banglerun/ChangeLog b/apps/banglerun/ChangeLog new file mode 100755 index 000000000..b96e5af7a --- /dev/null +++ b/apps/banglerun/ChangeLog @@ -0,0 +1,5 @@ +0.01: First release +0.02: Bugfix time: Reset minutes to 0 when hitting 60 +0.03: Fix distance >=10 km (fix #529) +0.04: Use offscreen buffer for flickerless updates +0.05: Complete rewrite. New UI, GPS & HRM Kalman filters, activity logging diff --git a/apps/banglerun/app-icon.js b/apps/banglerun/app-icon.js new file mode 100644 index 000000000..0ccbedab4 --- /dev/null +++ b/apps/banglerun/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwMB/4ACx4ED/0DApP8AqAXB84GDg/DAgXj/+DCAUABgIFB4EAv4FCwEAj0PAoJPBgwFEgEfDgMOAoM/AoMegFAAoP8jkA8F/AoM8gP4DgP4nBvD/F4KQfwuAFE+A/CAoPgAofx8A/CKYRwELIIFDLII6BAoZSBLIYeC/0BwAFDgfAGAQFBHgf8g4BBIIUH/wFBSYMPAoXwAog/Bj4FEv4FDDQQCBQoQFCZYYFi/6KE/+P/4A=")) diff --git a/apps/banglerun/app.js b/apps/banglerun/app.js new file mode 100644 index 000000000..07e8aa135 --- /dev/null +++ b/apps/banglerun/app.js @@ -0,0 +1 @@ +!function(){"use strict";const t={STOP:63488,PAUSE:65504,RUN:2016};function n(t,n,r){g.setColor(0),g.fillRect(n-60,r,n+60,r+30),g.setColor(65535),g.drawString(t,n,r)}function r(r){var e;g.setFontVector(30),g.setFontAlign(0,-1,0),n((r.distance/1e3).toFixed(2),60,55),n(function(t){const n=Math.round(t),r=Math.floor(n/3600),e=Math.floor(n/60)%60,a=n%60;return(r?r+":":"")+("0"+e).substr(-2)+":"+("0"+a).substr(-2)}(r.duration),180,55),n(function(t){if(t<.1667)return"__'__\"";const n=Math.round(1e3/t),r=Math.floor(n/60),e=n%60;return("0"+r).substr(-2)+"'"+("0"+e).substr(-2)+'"'}(r.speed),60,115),n(r.hr.toFixed(0),180,115),n(r.steps.toFixed(0),60,175),n(r.cadence.toFixed(0),180,175),g.setFont("6x8",2),g.setColor(r.gpsValid?2016:63488),g.fillRect(0,216,80,240),g.setColor(0),g.drawString("GPS",40,220),g.setColor(65535),g.fillRect(80,216,160,240),g.setColor(0),g.drawString(("0"+(e=new Date).getHours()).substr(-2)+":"+("0"+e.getMinutes()).substr(-2),120,220),g.setColor(t[r.status]),g.fillRect(160,216,240,240),g.setColor(0),g.drawString(r.status,200,220)}function e(t){g.clear(),g.setColor(50712),g.setFont("6x8",2),g.setFontAlign(0,-1,0),g.drawString("DIST (KM)",60,32),g.drawString("TIME",180,32),g.drawString("PACE",60,92),g.drawString("HEART",180,92),g.drawString("STEPS",60,152),g.drawString("CADENCE",180,152),r(t),Bangle.drawWidgets()}var a;function o(t){t.status===a.Stopped&&function(t){const n=(new Date).toISOString().replace(/[-:]/g,""),r=`banglerun_${n.substr(2,6)}_${n.substr(9,6)}`;t.file=require("Storage").open(r,"w"),t.file.write(["timestamp","latitude","longitude","altitude","duration","distance","heartrate","steps"].join(","))}(t),t.status===a.Running?t.status=a.Paused:t.status=a.Running,r(t)}!function(t){t.Stopped="STOP",t.Paused="PAUSE",t.Running="RUN"}(a||(a={}));function s(t){const n=t.indexOf(".")-2;return(parseInt(t.substr(0,n))+parseFloat(t.substr(n))/60)*Math.PI/180}const i={fix:NaN,lat:NaN,lon:NaN,alt:NaN,vel:NaN,dop:NaN,gpsValid:!1,x:NaN,y:NaN,z:NaN,v:NaN,t:NaN,dt:NaN,pError:NaN,vError:NaN,hr:60,hrError:100,file:null,drawing:!1,status:a.Stopped,duration:0,distance:0,speed:0,steps:0,cadence:0};var d;d=i,Bangle.on("GPS-raw",t=>function(t,n){const e=n.split(",");switch(e[0].substr(3,3)){case"GGA":t.lat=s(e[2])*("N"===e[3]?1:-1),t.lon=s(e[4])*("E"===e[5]?1:-1),t.alt=parseFloat(e[9]);break;case"VTG":t.vel=parseFloat(e[7])/3.6;break;case"GSA":t.fix=parseInt(e[2]),t.dop=parseFloat(e[15]);break;case"GLL":t.gpsValid=3===t.fix&&t.dop<=5,function(t){const n=Date.now(),r=(n-t.t)/1e3;if(t.t=n,t.dt+=r,t.status===a.Running&&(t.duration+=r),!t.gpsValid)return;const e=6371008.8+t.alt,o=e*Math.cos(t.lat)*Math.cos(t.lon),s=e*Math.cos(t.lat)*Math.sin(t.lon),i=e*Math.sin(t.lat),d=t.vel;if(!t.x)return t.x=o,t.y=s,t.z=i,t.v=d,t.pError=2.5*t.dop,void(t.vError=.05*t.dop);const u=o-t.x,l=s-t.y,g=i-t.z,c=d-t.v,p=Math.sqrt(u*u+l*l+g*g),f=Math.abs(c);t.pError+=t.v*t.dt,t.dt=0;const N=p+2.5*t.dop,h=f+.05*t.dop,S=t.pError/(t.pError+N),E=t.vError/(t.vError+h);t.x+=u*S,t.y+=l*S,t.z+=g*S,t.v+=c*E,t.pError+=(N-t.pError)*S,t.vError+=(h-t.vError)*E;const w=Math.sqrt(t.x*t.x+t.y*t.y+t.z*t.z);t.lat=180*Math.asin(t.z/w)/Math.PI,t.lon=180*Math.atan2(t.y,t.x)/Math.PI||0,t.alt=w-6371008.8,t.status===a.Running&&(t.distance+=p*S,t.speed=t.distance/t.duration||0,t.cadence=60*t.steps/t.duration||0)}(t),r(t),t.gpsValid&&t.status===a.Running&&function(t){t.file.write("\n"),t.file.write([Date.now().toFixed(0),t.lat.toFixed(6),t.lon.toFixed(6),t.alt.toFixed(2),t.duration.toFixed(0),t.distance.toFixed(2),t.hr.toFixed(0),t.steps.toFixed(0)].join(","))}(t)}}(d,t)),Bangle.setGPSPower(1),function(t){Bangle.on("HRM",n=>function(t,n){if(0===n.confidence)return;const r=n.bpm-t.hr,e=Math.abs(r)+101-n.confidence,a=t.hrError/(t.hrError+e);t.hr+=r*a,t.hrError+=(e-t.hrError)*a}(t,n)),Bangle.setHRMPower(1)}(i),function(t){Bangle.on("step",()=>function(t){t.status===a.Running&&(t.steps+=1)}(t))}(i),function(t){Bangle.loadWidgets(),Bangle.on("lcdPower",n=>{t.drawing=n,n&&e(t)}),e(t)}(i),setWatch(()=>o(i),BTN1,{repeat:!0,edge:"falling"}),setWatch(()=>function(t){t.status===a.Paused&&function(t){t.duration=0,t.distance=0,t.speed=0,t.steps=0,t.cadence=0}(t),t.status===a.Running?t.status=a.Paused:t.status=a.Stopped,r(t)}(i),BTN3,{repeat:!0,edge:"falling"})}(); diff --git a/apps/banglerun/banglerun.png b/apps/banglerun/banglerun.png new file mode 100644 index 000000000..bf2cd8af3 Binary files /dev/null and b/apps/banglerun/banglerun.png differ diff --git a/apps/banglerun/jasmine.json b/apps/banglerun/jasmine.json new file mode 100644 index 000000000..813363b27 --- /dev/null +++ b/apps/banglerun/jasmine.json @@ -0,0 +1,6 @@ +{ + "spec_dir": "test", + "spec_files": [ + "**/*.spec.ts" + ] +} \ No newline at end of file diff --git a/apps/banglerun/package.json b/apps/banglerun/package.json new file mode 100644 index 000000000..ba75bd8fe --- /dev/null +++ b/apps/banglerun/package.json @@ -0,0 +1,24 @@ +{ + "name": "banglerun", + "version": "0.5.0", + "description": "Bangle.js app for running sessions", + "main": "app.js", + "types": "app.d.ts", + "scripts": { + "build": "rollup -c", + "test": "ts-node -P tsconfig.spec.json node_modules/jasmine/bin/jasmine --config=jasmine.json" + }, + "author": "Stefano Baldan", + "license": "ISC", + "devDependencies": { + "@rollup/plugin-typescript": "^4.1.1", + "@types/jasmine": "^3.5.10", + "jasmine": "^3.5.0", + "rollup": "^2.10.2", + "rollup-plugin-terser": "^5.3.0", + "terser": "^4.7.0", + "ts-node": "^8.10.2", + "tslib": "^2.0.0", + "typescript": "^3.9.2" + } +} diff --git a/apps/banglerun/rollup.config.js b/apps/banglerun/rollup.config.js new file mode 100644 index 000000000..f7027eb2b --- /dev/null +++ b/apps/banglerun/rollup.config.js @@ -0,0 +1,15 @@ +import typescript from '@rollup/plugin-typescript'; +import { terser } from 'rollup-plugin-terser'; + +export default { + input: './src/app.ts', + output: { + dir: '.', + format: 'iife', + name: 'banglerun' + }, + plugins: [ + typescript(), + terser(), + ] +}; diff --git a/apps/banglerun/src/activity.ts b/apps/banglerun/src/activity.ts new file mode 100644 index 000000000..c1a01f30b --- /dev/null +++ b/apps/banglerun/src/activity.ts @@ -0,0 +1,41 @@ +import { draw } from './display'; +import { initLog } from './log'; +import { ActivityStatus, AppState } from './state'; + +function startActivity(state: AppState): void { + if (state.status === ActivityStatus.Stopped) { + initLog(state); + } + + if (state.status === ActivityStatus.Running) { + state.status = ActivityStatus.Paused; + } else { + state.status = ActivityStatus.Running; + } + + draw(state); +} + +function stopActivity(state: AppState): void { + if (state.status === ActivityStatus.Paused) { + clearActivity(state); + } + + if (state.status === ActivityStatus.Running) { + state.status = ActivityStatus.Paused; + } else { + state.status = ActivityStatus.Stopped; + } + + draw(state); +} + +function clearActivity(state: AppState): void { + state.duration = 0; + state.distance = 0; + state.speed = 0; + state.steps = 0; + state.cadence = 0; +} + +export { clearActivity, startActivity, stopActivity }; diff --git a/apps/banglerun/src/app.ts b/apps/banglerun/src/app.ts new file mode 100644 index 000000000..7093e24e0 --- /dev/null +++ b/apps/banglerun/src/app.ts @@ -0,0 +1,20 @@ +import { startActivity, stopActivity } from './activity'; +import { initDisplay } from './display'; +import { initGps } from './gps'; +import { initHrm } from './hrm'; +import { initState } from './state'; +import { initStep } from './step'; + +declare var BTN1: any; +declare var BTN3: any; +declare var setWatch: any; + +const appState = initState(); + +initGps(appState); +initHrm(appState); +initStep(appState); +initDisplay(appState); + +setWatch(() => startActivity(appState), BTN1, { repeat: true, edge: 'falling' }); +setWatch(() => stopActivity(appState), BTN3, { repeat: true, edge: 'falling' }); diff --git a/apps/banglerun/src/display.ts b/apps/banglerun/src/display.ts new file mode 100644 index 000000000..baa370860 --- /dev/null +++ b/apps/banglerun/src/display.ts @@ -0,0 +1,114 @@ +import { AppState } from './state'; + +declare var Bangle: any; +declare var g: any; + +const STATUS_COLORS = { + 'STOP': 0xF800, + 'PAUSE': 0xFFE0, + 'RUN': 0x07E0, +} + +function initDisplay(state: AppState): void { + Bangle.loadWidgets(); + Bangle.on('lcdPower', (on: boolean) => { + state.drawing = on; + if (on) { + drawAll(state); + } + }); + drawAll(state); +} + +function drawBackground(): void { + g.clear(); + g.setColor(0xC618); + g.setFont('6x8', 2); + g.setFontAlign(0, -1, 0); + g.drawString('DIST (KM)', 60, 32); + g.drawString('TIME', 180, 32); + g.drawString('PACE', 60, 92); + g.drawString('HEART', 180, 92); + g.drawString('STEPS', 60, 152); + g.drawString('CADENCE', 180, 152); +} + +function drawValue(value: string, x: number, y: number) { + g.setColor(0x0000); + g.fillRect(x - 60, y, x + 60, y + 30); + g.setColor(0xFFFF); + g.drawString(value, x, y); +} + +function draw(state: AppState): void { + g.setFontVector(30); + g.setFontAlign(0, -1, 0); + + drawValue(formatDistance(state.distance), 60, 55); + drawValue(formatTime(state.duration), 180, 55); + drawValue(formatPace(state.speed), 60, 115); + drawValue(state.hr.toFixed(0), 180, 115); + drawValue(state.steps.toFixed(0), 60, 175); + drawValue(state.cadence.toFixed(0), 180, 175); + + g.setFont('6x8', 2); + + g.setColor(state.gpsValid ? 0x07E0 : 0xF800); + g.fillRect(0, 216, 80, 240); + g.setColor(0x0000); + g.drawString('GPS', 40, 220); + + g.setColor(0xFFFF); + g.fillRect(80, 216, 160, 240); + g.setColor(0x0000); + g.drawString(formatClock(new Date()), 120, 220); + + g.setColor(STATUS_COLORS[state.status]); + g.fillRect(160, 216, 240, 240); + g.setColor(0x0000); + g.drawString(state.status, 200, 220); +} + +function drawAll(state: AppState) { + drawBackground(); + draw(state); + Bangle.drawWidgets(); +} + +function formatClock(date: Date): string { + return ('0' + date.getHours()).substr(-2) + ':' + ('0' + date.getMinutes()).substr(-2); +} + +function formatDistance(meters: number): string { + return (meters / 1000).toFixed(2); +} + +function formatPace(speed: number): string { + if (speed < 0.1667) { + return `__'__"`; + } + const pace = Math.round(1000 / speed); + const min = Math.floor(pace / 60); + const sec = pace % 60; + return ('0' + min).substr(-2) + `'` + ('0' + sec).substr(-2) + `"`; +} + +function formatTime(time: number): string { + const seconds = Math.round(time); + const hrs = Math.floor(seconds / 3600); + const min = Math.floor(seconds / 60) % 60; + const sec = seconds % 60; + return (hrs ? hrs + ':' : '') + ('0' + min).substr(-2) + `:` + ('0' + sec).substr(-2); +} + +export { + draw, + drawAll, + drawBackground, + drawValue, + formatClock, + formatDistance, + formatPace, + formatTime, + initDisplay, +}; diff --git a/apps/banglerun/src/gps.ts b/apps/banglerun/src/gps.ts new file mode 100644 index 000000000..3c0ee120d --- /dev/null +++ b/apps/banglerun/src/gps.ts @@ -0,0 +1,120 @@ +import { draw } from './display'; +import { updateLog } from './log'; +import { ActivityStatus, AppState } from './state'; + +declare var Bangle: any; + +const EARTH_RADIUS = 6371008.8; +const POS_ACCURACY = 2.5; +const VEL_ACCURACY = 0.05; + +function initGps(state: AppState): void { + Bangle.on('GPS-raw', (nmea: string) => parseNmea(state, nmea)); + Bangle.setGPSPower(1); +} + +function parseCoordinate(coordinate: string): number { + const pivot = coordinate.indexOf('.') - 2; + const degrees = parseInt(coordinate.substr(0, pivot)); + const minutes = parseFloat(coordinate.substr(pivot)) / 60; + return (degrees + minutes) * Math.PI / 180; +} + +function parseNmea(state: AppState, nmea: string): void { + const tokens = nmea.split(','); + const sentence = tokens[0].substr(3, 3); + + switch (sentence) { + case 'GGA': + state.lat = parseCoordinate(tokens[2]) * (tokens[3] === 'N' ? 1 : -1); + state.lon = parseCoordinate(tokens[4]) * (tokens[5] === 'E' ? 1 : -1); + state.alt = parseFloat(tokens[9]); + break; + case 'VTG': + state.vel = parseFloat(tokens[7]) / 3.6; + break; + case 'GSA': + state.fix = parseInt(tokens[2]); + state.dop = parseFloat(tokens[15]); + break; + case 'GLL': + state.gpsValid = state.fix === 3 && state.dop <= 5; + updateGps(state); + draw(state); + if (state.gpsValid && state.status === ActivityStatus.Running) { + updateLog(state); + } + break; + default: + break; + } +} + +function updateGps(state: AppState): void { + const t = Date.now(); + const dt = (t - state.t) / 1000; + + state.t = t; + state.dt += dt; + + if (state.status === ActivityStatus.Running) { + state.duration += dt; + } + + if (!state.gpsValid) { + return; + } + + const r = EARTH_RADIUS + state.alt; + const x = r * Math.cos(state.lat) * Math.cos(state.lon); + const y = r * Math.cos(state.lat) * Math.sin(state.lon); + const z = r * Math.sin(state.lat); + const v = state.vel; + + if (!state.x) { + state.x = x; + state.y = y; + state.z = z; + state.v = v; + state.pError = state.dop * POS_ACCURACY; + state.vError = state.dop * VEL_ACCURACY; + return; + } + + const dx = x - state.x; + const dy = y - state.y; + const dz = z - state.z; + const dv = v - state.v; + const dpMag = Math.sqrt(dx * dx + dy * dy + dz * dz); + const dvMag = Math.abs(dv); + + state.pError += state.v * state.dt; + state.dt = 0; + + const pError = dpMag + state.dop * POS_ACCURACY; + const vError = dvMag + state.dop * VEL_ACCURACY; + + const pGain = state.pError / (state.pError + pError); + const vGain = state.vError / (state.vError + vError); + + state.x += dx * pGain; + state.y += dy * pGain; + state.z += dz * pGain; + state.v += dv * vGain; + state.pError += (pError - state.pError) * pGain; + state.vError += (vError - state.vError) * vGain; + + const pMag = Math.sqrt(state.x * state.x + state.y * state.y + state.z * state.z); + + state.lat = Math.asin(state.z / pMag) * 180 / Math.PI; + state.lon = (Math.atan2(state.y, state.x) * 180 / Math.PI) || 0; + state.alt = pMag - EARTH_RADIUS; + + if (state.status === ActivityStatus.Running) { + state.distance += dpMag * pGain; + state.speed = (state.distance / state.duration) || 0; + state.cadence = (60 * state.steps / state.duration) || 0; + } +} + +export { initGps, parseCoordinate, parseNmea, updateGps }; diff --git a/apps/banglerun/src/hrm.ts b/apps/banglerun/src/hrm.ts new file mode 100644 index 000000000..ac43f4625 --- /dev/null +++ b/apps/banglerun/src/hrm.ts @@ -0,0 +1,29 @@ +import { AppState } from './state'; + +interface HrmData { + bpm: number; + confidence: number; + raw: string; +} + +declare var Bangle: any; + +function initHrm(state: AppState) { + Bangle.on('HRM', (hrm: HrmData) => updateHrm(state, hrm)); + Bangle.setHRMPower(1); +} + +function updateHrm(state: AppState, hrm: HrmData) { + if (hrm.confidence === 0) { + return; + } + + const dHr = hrm.bpm - state.hr; + const hrError = Math.abs(dHr) + 101 - hrm.confidence; + const hrGain = state.hrError / (state.hrError + hrError); + + state.hr += dHr * hrGain; + state.hrError += (hrError - state.hrError) * hrGain; +} + +export { initHrm, updateHrm }; diff --git a/apps/banglerun/src/log.ts b/apps/banglerun/src/log.ts new file mode 100644 index 000000000..fb0676121 --- /dev/null +++ b/apps/banglerun/src/log.ts @@ -0,0 +1,37 @@ +import { AppState } from './state'; + +declare var require: any; + +function initLog(state: AppState): void { + const datetime = new Date().toISOString().replace(/[-:]/g, ''); + const date = datetime.substr(2, 6); + const time = datetime.substr(9, 6); + const filename = `banglerun_${date}_${time}`; + state.file = require('Storage').open(filename, 'w'); + state.file.write([ + 'timestamp', + 'latitude', + 'longitude', + 'altitude', + 'duration', + 'distance', + 'heartrate', + 'steps', + ].join(',')); +} + +function updateLog(state: AppState): void { + state.file.write('\n'); + state.file.write([ + Date.now().toFixed(0), + state.lat.toFixed(6), + state.lon.toFixed(6), + state.alt.toFixed(2), + state.duration.toFixed(0), + state.distance.toFixed(2), + state.hr.toFixed(0), + state.steps.toFixed(0), + ].join(',')); +} + +export { initLog, updateLog }; diff --git a/apps/banglerun/src/state.ts b/apps/banglerun/src/state.ts new file mode 100644 index 000000000..ddb60e1ad --- /dev/null +++ b/apps/banglerun/src/state.ts @@ -0,0 +1,87 @@ +enum ActivityStatus { + Stopped = 'STOP', + Paused = 'PAUSE', + Running = 'RUN', +} + +interface AppState { + // GPS NMEA data + fix: number; + lat: number; + lon: number; + alt: number; + vel: number; + dop: number; + gpsValid: boolean; + + // GPS Kalman data + x: number; + y: number; + z: number; + v: number; + t: number; + dt: number; + pError: number; + vError: number; + + // HRM data + hr: number, + hrError: number, + + // Logger data + file: File; + + // Drawing data + drawing: boolean; + + // Activity data + status: ActivityStatus; + duration: number; + distance: number; + speed: number; + steps: number; + cadence: number; +} + +interface File { + read: Function; + write: Function; + erase: Function; +} + +function initState(): AppState { + return { + fix: NaN, + lat: NaN, + lon: NaN, + alt: NaN, + vel: NaN, + dop: NaN, + gpsValid: false, + + x: NaN, + y: NaN, + z: NaN, + v: NaN, + t: NaN, + dt: NaN, + pError: NaN, + vError: NaN, + + hr: 60, + hrError: 100, + + file: null, + + drawing: false, + + status: ActivityStatus.Stopped, + duration: 0, + distance: 0, + speed: 0, + steps: 0, + cadence: 0, + } +} + +export { ActivityStatus, AppState, File, initState }; diff --git a/apps/banglerun/src/step.ts b/apps/banglerun/src/step.ts new file mode 100644 index 000000000..c7fcb61ea --- /dev/null +++ b/apps/banglerun/src/step.ts @@ -0,0 +1,15 @@ +import { ActivityStatus, AppState } from './state'; + +declare var Bangle: any; + +function initStep(state: AppState) { + Bangle.on('step', () => updateStep(state)); +} + +function updateStep(state: AppState) { + if (state.status === ActivityStatus.Running) { + state.steps += 1; + } +} + +export { initStep, updateStep }; diff --git a/apps/banglerun/tsconfig.json b/apps/banglerun/tsconfig.json new file mode 100644 index 000000000..a341a5a5e --- /dev/null +++ b/apps/banglerun/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "module": "es2015", + "noImplicitAny": true, + "target": "es2015" + }, + "include": [ + "src" + ] +} diff --git a/apps/banglerun/tsconfig.spec.json b/apps/banglerun/tsconfig.spec.json new file mode 100644 index 000000000..136ae137b --- /dev/null +++ b/apps/banglerun/tsconfig.spec.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "module": "commonjs", + "noImplicitAny": true, + "target": "es2015" + }, + "include": [ + "test" + ] +} diff --git a/apps/barclock/ChangeLog b/apps/barclock/ChangeLog index 2e0fd088c..616ee66e9 100644 --- a/apps/barclock/ChangeLog +++ b/apps/barclock/ChangeLog @@ -2,3 +2,4 @@ 0.02: Apply locale, 12-hour setting 0.03: Fix dates drawing over each other at midnight 0.04: Small bugfix +0.05: Clock does not start if app Languages is not installed \ No newline at end of file diff --git a/apps/barclock/clock-bar.js b/apps/barclock/clock-bar.js index da436daee..0f2609298 100644 --- a/apps/barclock/clock-bar.js +++ b/apps/barclock/clock-bar.js @@ -12,7 +12,12 @@ date.setMonth(1, 3) // februari: months are zero-indexed const localized = locale.date(date, true) locale.dayFirst = /3.*2/.test(localized) - locale.hasMeridian = (locale.meridian(date) !== '') + + locale.hasMeridian = false + if(typeof locale.meridian === 'function') { // function does not exists if languages app is not installed + locale.hasMeridian = (locale.meridian(date) !== '') + } + } const screen = { width: g.getWidth(), diff --git a/apps/batchart/ChangeLog b/apps/batchart/ChangeLog index 439d877be..31c386684 100644 --- a/apps/batchart/ChangeLog +++ b/apps/batchart/ChangeLog @@ -5,4 +5,6 @@ 0.05: Display temperature and LCD state in chart 0.06: Fixes widget events and charting of component states 0.07: Improve logging and charting of component states and add widget icon -0.08: Fix for Home button in the app and README added. \ No newline at end of file +0.08: Fix for Home button in the app and README added. +0.09: Fix failing dismissal of Gadgetbridge notifications, record (coarse) bluetooth state +0.10: Remove widget icon and improve listener and setInterval handling for widget (might help with https://github.com/espruino/BangleApps/issues/381) \ No newline at end of file diff --git a/apps/batchart/app.js b/apps/batchart/app.js index 2d0d8e585..472fb3a8a 100644 --- a/apps/batchart/app.js +++ b/apps/batchart/app.js @@ -8,7 +8,7 @@ const GraphXMax = GraphXZero + MaxValueCount; const GraphLcdY = GraphYZero + 10; const GraphCompassY = GraphYZero + 16; -// const GraphBluetoothY = GraphYZero + 22; +const GraphBluetoothY = GraphYZero + 22; const GraphGpsY = GraphYZero + 28; const GraphHrmY = GraphYZero + 34; @@ -175,13 +175,13 @@ function renderData(dataArray) { g.drawLine(GraphXZero + i, GraphCompassY, GraphXZero + i, GraphCompassY + 1); } - // // Bluetooth state - // if (switchables & switchableConsumers.lcd == switchableConsumers.lcd) { - // g.setColor(0, 0, 1); - // g.setFontAlign(1, -1, 0); - // g.drawString("BLE", GraphXZero - GraphMarkerOffset, GraphBluetoothY - 2, true); - // g.drawLine(GraphXZero + i, GraphBluetoothY, GraphXZero + i, GraphBluetoothY + 1); - // } + // Bluetooth state + if (parseInt(dataInfo[switchabelsIndex]) & switchableConsumers.bluetooth) { + g.setColor(0, 0, 1); + g.setFontAlign(1, -1, 0); + g.drawString("BLE", GraphXZero - GraphMarkerOffset, GraphBluetoothY - 2, true); + g.drawLine(GraphXZero + i, GraphBluetoothY, GraphXZero + i, GraphBluetoothY + 1); + } // Gps state if (parseInt(dataInfo[switchabelsIndex]) & switchableConsumers.gps) { diff --git a/apps/batchart/widget.js b/apps/batchart/widget.js index 1b8ce79ba..d6e00b283 100644 --- a/apps/batchart/widget.js +++ b/apps/batchart/widget.js @@ -1,6 +1,7 @@ (() => { + let recordingInterval = null; const Storage = require("Storage"); - + const switchableConsumers = { none: 0, lcd: 1, @@ -14,53 +15,44 @@ const recordingInterval10Min = 60 * 10 * 1000; const recordingInterval1Min = 60 * 1000; //For testing const recordingInterval10S = 10 * 1000; //For testing - var recordingInterval = null; var compassEventReceived = false; var gpsEventReceived = false; var hrmEventReceived = false; - // draw your widget function draw() { - let x = this.x; - let y = this.y; - - g.setColor(0, 1, 0); - g.fillPoly([x + 5, y, x + 5, y + 4, x + 1, y + 4, x + 1, y + 20, x + 18, y + 20, x + 18, y + 4, x + 13, y + 4, x + 13, y], true); - - g.setColor(0, 0, 0); - g.drawPoly([x + 5, y + 6, x + 8, y + 12, x + 13, y + 12, x + 16, y + 18], false); - - g.reset(); + // void } - function onMag() { + function batteryChartOnMag() { compassEventReceived = true; // Stop handling events when no longer necessarry - Bangle.removeListener("mag", onMag); + Bangle.removeListener("mag", batteryChartOnMag); } - function onGps() { + function batterChartOnGps() { gpsEventReceived = true; - Bangle.removeListener("GPS", onGps); + Bangle.removeListener("GPS", batterChartOnGps); } - function onHrm() { + function batteryChartOnHrm() { hrmEventReceived = true; - Bangle.removeListener("HRM", onHrm); + Bangle.removeListener("HRM", batteryChartOnHrm); } function getEnabledConsumersValue() { // Wait for an event from each of the devices to see if they are switched on var enabledConsumers = switchableConsumers.none; - Bangle.on('mag', onMag); - Bangle.on('GPS', onGps); - Bangle.on('HRM', onHrm); + Bangle.on('mag', batteryChartOnMag); + Bangle.on('GPS', batterChartOnGps); + Bangle.on('HRM', batteryChartOnHrm); // Wait two seconds, that should be enough for each of the events to get raised once setTimeout(() => { - Bangle.removeAllListeners(); + Bangle.removeListener('mag', batteryChartOnMag); + Bangle.removeListener('GPS', batterChartOnGps); + Bangle.removeListener('HRM', batteryChartOnHrm); }, 2000); if (Bangle.isLCDOn()) @@ -71,8 +63,10 @@ enabledConsumers = enabledConsumers | switchableConsumers.gps; if (hrmEventReceived) enabledConsumers = enabledConsumers | switchableConsumers.hrm; - //if (Bangle.isBluetoothOn()) - // enabledConsumers = enabledConsumers | switchableConsumers.bluetooth; + + // Very coarse first approach to check if the BLE device is on. + if (NRF.getSecurityStatus().connected) + enabledConsumers = enabledConsumers | switchableConsumers.bluetooth; // Reset the event registration vars compassEventReceived = false; @@ -110,19 +104,20 @@ } function reload() { - WIDGETS.batchart.width = 24; + console.log("Reloading BatteryChart widget"); + WIDGETS["batchart"].width = 0; + + if (recordingInterval) { + clearInterval(recordingInterval); + recordingInterval = null; + } recordingInterval = setInterval(logBatteryData, recordingInterval10Min); - - logBatteryData(); } // add the widget - WIDGETS.batchart = { - area: "tl", width: 24, draw: draw, reload: function () { - reload(); - Bangle.drawWidgets(); - } + WIDGETS["batchart"] = { + area: "tl", width: 0, draw: draw, reload: reload }; reload(); diff --git a/apps/bclock/clock-binary.js b/apps/bclock/clock-binary.js index 98191f364..833aa00f6 100644 --- a/apps/bclock/clock-binary.js +++ b/apps/bclock/clock-binary.js @@ -6,98 +6,98 @@ const colpos = canvasWidth / numberOfColumns - 10; const binSize = (canvasWidth / numberOfColumns) / 3; const findBinary = target => { - return [ - [0, 0, 0, 0], // 0 - [1, 0, 0, 0], // 1 - [0, 1, 0, 0], // 2 - [1, 1, 0, 0], // 3 - [0, 0, 1, 0], // 4 - [1, 0, 1, 0], // 5 - [0, 1, 1, 0], // 6 - [1, 1, 1, 0], // 7 - [0, 0, 0, 1], // 8 - [1, 0, 0, 1], // 9 - ][target]; + return [ + [0, 0, 0, 0], // 0 + [1, 0, 0, 0], // 1 + [0, 1, 0, 0], // 2 + [1, 1, 0, 0], // 3 + [0, 0, 1, 0], // 4 + [1, 0, 1, 0], // 5 + [0, 1, 1, 0], // 6 + [1, 1, 1, 0], // 7 + [0, 0, 0, 1], // 8 + [1, 0, 0, 1], // 9 + ][target]; }; const getCurrentTime = () => { - const flattenArray = (array = []) => [].concat.apply([], array); - const format = number => { - const numberStr = number.toString(); - return numberStr.length === 1 ? ["0", numberStr] : numberStr.split(""); - }; - const now = new Date(); - return flattenArray([now.getHours(), now.getMinutes(), now.getSeconds()].map(format)); + const flattenArray = (array = []) => [].concat.apply([], array); + const format = number => { + const numberStr = number.toString(); + return numberStr.length === 1 ? ["0", numberStr] : numberStr.split(""); + }; + const now = new Date(); + return flattenArray([now.getHours(), now.getMinutes(), now.getSeconds()].map(format)); }; let prevFrame = []; const drawColumn = (position = 0, column = [0, 0, 0, 0]) => { - const maxDotsPerColumn = [2, 4, 3, 4, 3, 4]; + const maxDotsPerColumn = [2, 4, 3, 4, 3, 4]; - const columnPos = position * colpos; - let pos = colpos / 2 + 45; - const frame = column.reverse(); - const drawDot = fn => g[fn]((columnPos + colpos / 2), pos, binSize); + const columnPos = position * colpos; + let pos = colpos / 2 + 45; + const frame = column.reverse(); + const drawDot = fn => g[fn]((columnPos + colpos / 2), pos, binSize); - for (let i = 0; i < frame.length; i += 1) { - if (i + maxDotsPerColumn[position] >= 4 || drawFullGrid) { - if (prevFrame && prevFrame[position] && prevFrame[position][i]) { - if (frame[i] !== prevFrame[position][i]) { - // subsequent draw - g.clearRect((columnPos + colpos / 2) - 15, pos - 15, (columnPos + colpos / 2) + 20, pos + 20); - if (frame[i]) { - drawDot('fillCircle'); - } else { - drawDot('drawCircle'); - } - } - } else { - // First draw - if (frame[i]) { - drawDot('fillCircle'); - } else { - drawDot('drawCircle'); - } - } + for (let i = 0; i < frame.length; i += 1) { + if (i + maxDotsPerColumn[position] >= 4 || drawFullGrid) { + if (prevFrame && prevFrame[position] && prevFrame[position][i]) { + if (frame[i] !== prevFrame[position][i]) { + // subsequent draw + g.clearRect((columnPos + colpos / 2) - 15, pos - 15, (columnPos + colpos / 2) + 20, pos + 20); + if (frame[i]) { + drawDot('fillCircle'); + } else { + drawDot('drawCircle'); + } } - pos += colpos; + } else { + // First draw + if (frame[i]) { + drawDot('fillCircle'); + } else { + drawDot('drawCircle'); + } + } } + pos += colpos; + } }; const drawClock = () => { - const data = getCurrentTime().map(findBinary); - for (let i = 0; i < data.length; i += 1) { - drawColumn(i, data[i]); - } - prevFrame = data; + const data = getCurrentTime().map(findBinary); + for (let i = 0; i < data.length; i += 1) { + drawColumn(i, data[i]); + } + prevFrame = data; }; // Themes const drawTheme = (idx) => () => { - idx += 1; - const themes = [ - [[0, 0, 0], [1, 1, 1]], - [[1, 1, 1], [0, 0, 0]], - [[0, 0, 0], [1, 0, 0]], - [[0, 0, 0], [0, 1, 0]], - [[0, 0, 0], [0, 0, 1]], - ]; - if (idx >= themes.length) idx = 0; - const color = themes[idx]; - g.setBgColor.apply(g, color[0]); - g.setColor.apply(g, color[1]); - g.clear(); + idx += 1; + const themes = [ + [[0, 0, 0], [1, 1, 1]], + [[1, 1, 1], [0, 0, 0]], + [[0, 0, 0], [1, 0, 0]], + [[0, 0, 0], [0, 1, 0]], + [[0, 0, 0], [0, 0, 1]], + ]; + if (idx >= themes.length) idx = 0; + const color = themes[idx]; + g.setBgColor.apply(g, color[0]); + g.setColor.apply(g, color[1]); + g.clear(); }; const nextTheme = drawTheme(0); setWatch(() => { - prevFrame = []; - Bangle.beep(); - nextTheme(); + prevFrame = []; + Bangle.beep(); + nextTheme(); }, BTN1, { repeat: true }); Bangle.on('lcdPower', on => { - if (on) drawClock(); + if (on) drawClock(); }); g.clear(); diff --git a/apps/beebclock/ChangeLog b/apps/beebclock/ChangeLog new file mode 100644 index 000000000..14dd12220 --- /dev/null +++ b/apps/beebclock/ChangeLog @@ -0,0 +1,2 @@ +0.01: Initial commit. Not very efficient, and widgets not working for some reason. +0.02: Fixes; widget support diff --git a/apps/beebclock/beebclock-icon.js b/apps/beebclock/beebclock-icon.js new file mode 100644 index 000000000..b4d173068 --- /dev/null +++ b/apps/beebclock/beebclock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkHA4dQAgcFgPyl8QDxgNE0EAggXGAgcFDQ0TBgQXBkcgBQURCw8GBYUj+AEBI430AgI7BBAVgCIU/if0DoMC+UfiwLBgUyEQRyGgEzmPzCIQvCBwMPj4rCAwJECAAUD+MvkEQgMhkRABgEvkaKIJAXzj49BBYMBBIOm+IIBgMVPQxiBn8xkAIDAYMBj6TBSIYyFhUPBoJRCF4RlBAoJRBBggSBIIgAI0qhCFgUB/4WFTIYDDFwJMCCAUSifzDoYsGBQJIBfoM0kIEBn81168CfAwACKwMS+UT+ovC/8gmRRCGQqQBRgUjocyB4YYBI4QrEDwRdCfAQ4EsD5DAA5dCDYbMDCoTPCBAsQaYprHRosR0ICBB4ZtDEYJZHM4X/kMKFAwSGAocBn8hkX/NBMFEAJXDAQMD+IcBkcwBIZ1EHgP/BgIzD17QBDYPwI4kCn8/mcjkUyCAQlCVocB+IqDC4IVBmYWBkVAVAkvaIboDqAGBCwMyIwM/I4IVBoYHBI4qzDI4egLYURiaiCO4UAl4bCMIJLEEAUj//zlVQgynBmNC/5LBcQsA0BXBCoNCeQkDKQX1X5Ef+clTQIkCT4URiJYBXwYlEirHGOAkAJYIvHEAUTNoadBegn/EYUCB4IjDiRtCCoWgEwj8BCQMCCAQkBAoMhkZJDC4kFh/yNAMyifzE4U/kMf+RRGM4beCp/xibLBqERj6EDboQjCT4beDmMhQwRNEQIoACiISCIYILCgKNCXgQXFGYoTBC4a/DgcmBoRLCEAMDCQQPBbwxVBmLDDGwUCj/wHY4ADn8TBwbYD+3xCY8AhQlB+M/JwS3BGIXzj5RENAS1Cj86YQUB+U/KIdvmB6FIw8Qg3yl5KCgcyMAgZFiNPOwYXDAoURL45LCiSLD+YXBAoTXDAAbTIL4oJCCIRdEDA1gI4ooFgAA==")) diff --git a/apps/beebclock/beebclock.js b/apps/beebclock/beebclock.js new file mode 100644 index 000000000..6ed4f532e --- /dev/null +++ b/apps/beebclock/beebclock.js @@ -0,0 +1,397 @@ +/* jshint esversion: 6 */ +// Beebclock +// © 2020, Tom Gidden +// https://github.com/tomgidden + +const storage = require("Storage"); +const filename = 'beebjson'; + +require('FontTeletext10x18Ascii').add(Graphics); + +// Double height text +Graphics.prototype.drawStringDH = function (txt, px, py, align, gw) { + let g2 = Graphics.createArrayBuffer(gw,18,1,{msb:true}); + g2.setFontTeletext10x18Ascii(); + let w = g2.stringWidth(txt); + let c = (w+3)>>2; + g2.drawString(txt); + let img = {width:w,height:1,transparent:0,buffer:new ArrayBuffer(c)}; + let a = new Uint8Array(img.buffer); + + let x; + switch (align) { + case 'C': x = px + (gw - w)/2; break; + case 'R': x = gw - w + px; break; + default: x = px; + } + + for (var y=0;y<18;y++) { + a.set(new Uint8Array(g2.buffer,gw*y/8,c)); + this.drawImage(img,x,py+y*2); + this.drawImage(img,x,py+1+y*2); + } +}; + +// Fill rectangle rotated around the centre +Graphics.prototype.fillRotRect = function (sina, cosa, cx, cy, x0, x1, y0, y1) { + let fn = Math.ceil; + return this.fillPoly([ + fn(cx - x0*cosa + y0*sina), fn(cy - x0*sina - y0*cosa), + fn(cx - x1*cosa + y0*sina), fn(cy - x1*sina - y0*cosa), + fn(cx - x1*cosa + y1*sina), fn(cy - x1*sina - y1*cosa), + fn(cx - x0*cosa + y1*sina), fn(cy - x0*sina - y1*cosa) + ]); +}; + +// Draw a line from r1,a to r2,a relative to cx+cy +Graphics.prototype.drawRotLine = function (sina, cosa, cx, cy, r1, r2) { + return this.drawLine( + cx + r1*sina, cy - r1*cosa, + cx + r2*sina, cy - r2*cosa + ); +}; + + +(function(g) { + // Display modes + // + // 0: full-screen + // 1: with widgets + // 2: centred on Bangle (v.1), no widgets or time/date + // 3: centred with time above + // 4: centred with date above + // 5: centred with time and date above + let mode; + + // R1, R2: Outer and inner radii of hour marks + // RC1, RC2: Outer and inner radii of hub + // CX, CY: Centre location, relative to buffer (not screen, necessarily) + // HW2, MW2: Half-width of hour and minute hand + // HR, MR: Length of hour and minute hand, relative to CX,CY + // M: Half-width of gap in hour marks + // HSCALE: Half-width of hour mark as function(0 { + const fw = R1 * 2; + const fh = R1 * 2; + const fw2 = R1; + const fh2 = R1; + let hs = []; + + // Wipe the image and start with white + G.clear(); + G.setColor(1,1,1); + + // Draw the hour marks. + for (let h=1; h<=12; h++) { + hs[h] = HSCALE(h); + G.fillRotRect(ss[h], cs[h], CX, CY, -hs[h], hs[h], R2, R1); + + } + + // Draw the hub + G.fillCircle(CX, CY, RC1); + + // Black + G.setColor(0,0,0); + + // Clear the centre of the hub + G.fillCircle(CX, CY, RC2); + + // Draw the gap in the hour marks + for (let h=1; h<=12; h++) { + G.fillRotRect(ss[h], cs[h], CX, CY, -M, M, R2-1, R1+1); + } + + // Back to white for future draw operations + G.setColor(1,1,1); + + // While the buffer remains full-screen, we may trim out the + // bottom of the image so we can shift the whole thing down for + // widgets. + const img = {width:GW,height:GH-TM,buffer:G.buffer}; + return img; + }; + + let hours, minutes, seconds, date; + + // Schedule event for calling at the start of the next second + const inOneSecond = (cb) => { + let now = new Date(); + clearTimeout(); + setTimeout(cb, 1000 - now.getMilliseconds()); + }; + + // Schedule event for calling at the start of the next minute + const inOneMinute = (cb) => { + let now = new Date(); + clearTimeout(); + setTimeout(cb, 60000 - (now.getSeconds() * 1000 + now.getMilliseconds())); + }; + + // Draw a fat hour/minute hand + const drawHand = (G, a, w2, r1, r2) => + G.fillRotRect(Math.sin(a), Math.cos(a), CX, CY, -w2, w2, r1, r2); + + // Redraw function + const drawAll = (force) => { + let now = new Date(); + + if (!faceImg) force = true; + + let face_changed = force; + let date_changed = false; + + tmp = hours; + hours = now.getHours(); + if (tmp !== hours) + face_changed = true; + + tmp = minutes; + minutes = now.getMinutes(); + if (tmp !== minutes) + face_changed = true; + + // If the face has been updated and/or needs a redraw, + // face_changed is true. + + let time_changed = face_changed; + + // If the screen needs an update, regardless of whether the face + // needs a redraw, time_changed is true. + + if (with_seconds) { + // If we're going by second, we always need an update. + seconds = now.getSeconds(); + time_changed = true; + } + + if (with_digital_date) { + // See if the date has changed. If it has, then we need a + // full-blown redraw of the screen and the face, plus text. + tmp = date; + date = now.getDate(); + if (tmp !== date) { + date_changed = true; + face_changed = true; // Should have changed anyway with hour/minute rollover + } + } + + if (face_changed) { + // Redraw the face and hands onto the buffer G1. + faceImg = drawFace(G1); + drawHand(G1, Math.PI*hours/6, HW2, RC1, HR); + drawHand(G1, Math.PI*minutes/30, MW2, RC1, MR); + } + + // Has the time updated? If so, we'll need to draw something. + if (time_changed) { + + // Are we adding text? + if (with_digital_date || with_digital_time) { + + // Construct the date/time text to add above the face + let d = now.toString(); + let da = d.toString().split(" "); + let txt; + + if (with_digital_time) { + txt = da[4].substr(0, 5); + if (with_digital_date) + G1.drawStringDH(txt+',', 24, 0, 'L', GW); + else + G1.drawStringDH(txt, 0, 0, 'C', GW); + } + + if (with_digital_date) { + let txt = [da[0], da[1], da[2]].join(" "); + if (with_digital_time) + G1.drawStringDH(txt, -24, 0, 'R', GW); + else + G1.drawStringDH(txt, 0, 0, 'C', GW); + } + } + + // If the time has updated, we need to _at least_ draw the + // image to the screen. + g.setColor(1,1,1); + g.drawImage({width:GW, + height:GH-TM, + buffer:G1.buffer}, 0, TM); + + // and possibly add the second hand + if (with_seconds) { + let a = 2.0 * Math.PI * seconds / 60.0; + g.drawRotLine(Math.sin(a), Math.cos(a), CX, CY+TM, RC1, R1); + } + + // Clock chime on the hour. + if (hours >= 0 && minutes === 0) + try { + Bangle.buzz(); + } catch (e) { } + + // And draw widgets if we're in that mode + if (with_widgets) + Bangle.drawWidgets(); + } + + // Schedule to repeat this. A `setTimeout(1000)` isn't good + // enough, as all the above might've taken some milliseconds and + // we don't want to drift. + if (with_seconds) + inOneSecond(drawAll); + else + inOneMinute(drawAll); + }; + + const setButtons = () => { + const opts = { repeat: true, edge:'rising', debounce:30}; + + // BTN1: enable/disable second hand + setWatch(changeSeconds, BTN1, opts); + + // BTN2: return to launcher + setWatch(Bangle.showLauncher, BTN2, { repeat:false, edge:'falling' }); + + // BTN3: change display mode + setWatch(function () { ++mode; setMode(); drawAll(true); }, BTN3, opts); + }; + + // Load display parameters based on `mode` + const setMode = () => { + // Normalize mode to 0 <= mode <= 5 + mode = (6+mode) % 6; + + // [R1, R2, RC1, RC2, HW2, MW3, HR, MR, M, HSCALE] = + const scales = [ + [120, 84, 17, 12.4, 4.6, 2.2, 8, 2, 1, h => (3.0 + Math.ceil(h/1.5)) ], + [102, 70, 14.6, 10.7, 3.88, 1.8, 8, 2, 1, h => (2.4 + Math.ceil(h/1.6)) ], + ]; + + if (mode < 3) { + // Face without time/date text. Might have widgets though. + with_digital_time = with_digital_date = false; + with_widgets = (mode == 1); + } + else { + // Face with time/date text, but no widgets + with_digital_time = (mode-2)&1; + with_digital_date = (mode-2)&2; + with_widgets = false; + } + + // Destructure the array to the global display parameters + let arr = scales[mode > 0 ? 1 : 0]; + R1 = arr[0]; + R2 = arr[1]; + RC1 = arr[2]; + RC2 = arr[3]; + HW2 = arr[4]; + MW2 = arr[5]; + HR = R2 - arr[6]; + MR = R1 - arr[7]; + M = arr[8]; + HSCALE = arr[9]; + TM = with_widgets ? 36 : 0; + + CX = GW/2; + CY = R1; + + // If we're in the small-face + text regime, we're going to buffer + // the full screen but draw the clock face further down to give + // space for the text. + // + // Compare with modes 0 (full-screen) and 1 (with_widgets==true) + // where the face is drawn at the top of the buffer, but drawn + // lower down the screen (so CY doesn't move) + if (mode > 1) { + CY += 36; + } + + // We only don't bother redrawing the face from modes 2 to 5, as + // they're the same. + if (!faceImg || mode<3) { + faceImg = undefined; + } + + // Store the settings for next time + try { + storage.writeJSON(filename, [mode,with_seconds]); + } catch (e) { + console.log(e); + } + + // Clear the screen: we need to make sure all parts are cleaned off. + g.clear(); + }; + + const changeSeconds = () => { + with_seconds = !with_seconds; + drawAll(true); + }; + + Bangle.loadWidgets(); + + // Restore mode + try { + conf = storage.readJSON(filename); + mode = conf[0]; + with_seconds = conf[1]; + } catch (e) { + console.log(e); + mode = 1; + } + + setButtons(); + setMode(); + drawAll(); + + Bangle.on('lcdPower', (on) => { + if (on) { + Bangle.loadWidgets(); + Bangle.drawWidgets(); + drawAll(); + } else { + clearTimeout(); + } + }); + +})(g); diff --git a/apps/beebclock/beebclock.png b/apps/beebclock/beebclock.png new file mode 100644 index 000000000..447ec9a41 Binary files /dev/null and b/apps/beebclock/beebclock.png differ diff --git a/apps/beer/app-icon.js b/apps/beer/app-icon.js new file mode 100644 index 000000000..c700b3bd2 --- /dev/null +++ b/apps/beer/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwghC/AB0O/4AG8AXNgYXHmAXl94XH+AXNn4XH/wXW+YX/C6oWHAAIXN7sz9vdAAoXN9sznvuAAXf/vuC53jC4Xd7wXQ93jn3u9vv9vt7wXT/4tBAgIXQ7wvCC4PgC5sO6czIQJfBC6PumaPDC6wwCC50NYAJcBVgIDBCxrAFbgYXP7yoDF6TADL4YXPVAIXCRyAXC7wXW9zwBC6cNC9zABC4gWQC653CR4fQC6x3TF6gXXI4M9d6wAEC9EN73dAAZfQgczAAkwC/4XXAH4")) diff --git a/apps/beer/beercompass.png b/apps/beer/app.png similarity index 100% rename from apps/beer/beercompass.png rename to apps/beer/app.png diff --git a/apps/beer/beercompass.html b/apps/beer/custom.html similarity index 94% rename from apps/beer/beercompass.html rename to apps/beer/custom.html index 434f0f6a9..a357ab378 100644 --- a/apps/beer/beercompass.html +++ b/apps/beer/custom.html @@ -33,7 +33,7 @@

If ok, Click

- + @@ -196,12 +196,10 @@ Bangle.on('mag', function(m) { Bangle.setCompassPower(1); Bangle.setGPSPower(1); g.clear();`; -var icon = `require("heatshrink").decompress(atob("mEwghC/AB0O/4AG8AXNgYXHmAXl94XH+AXNn4XH/wXW+YX/C6oWHAAIXN7sz9vdAAoXN9sznvuAAXf/vuC53jC4Xd7wXQ93jn3u9vv9vt7wXT/4tBAgIXQ7wvCC4PgC5sO6czIQJfBC6PumaPDC6wwCC50NYAJcBVgIDBCxrAFbgYXP7yoDF6TADL4YXPVAIXCRyAXC7wXW9zwBC6cNC9zABC4gWQC653CR4fQC6x3TF6gXXI4M9d6wAEC9EN73dAAZfQgczAAkwC/4XXAH4"))`; sendCustomizedApp({ storage:[ - {name:"beer.app.js", content:app}, - {name:"beer.img", content:icon, evaluate:true}, + {name:"beer.app.js", url:"app.js", content:app} ] }); }); diff --git a/apps/berlinc/ChangeLog b/apps/berlinc/ChangeLog index 7819dbe2a..a33332bc4 100644 --- a/apps/berlinc/ChangeLog +++ b/apps/berlinc/ChangeLog @@ -1 +1,2 @@ 0.02: Modified for use with new bootloader and firmware +0.03: Shrinked size to avoid cut-off edges on the physical device. BTN3: show date. BTN1: show time in decimal. diff --git a/apps/berlinc/README.md b/apps/berlinc/README.md new file mode 100644 index 000000000..1f86ad73e --- /dev/null +++ b/apps/berlinc/README.md @@ -0,0 +1,10 @@ +# Berlin Clock Watch Face + +This is a clock-face analogous to the [Berlin Clock](https://en.wikipedia.org/wiki/Mengenlehreuhr). + +## Usage + +* BTN1: toggle displaying the time in decimal figures (24 hour format) in the minutes fields. The first two fields are used for the hour and the last two fields for the minute. This might be a help when you're still familarizig yourself with this new way to express the time. +* BTN2: start the launcher +* BTN3: toggle displaying the current date (in ISO 8601 format) below the actual clock-face. + diff --git a/apps/berlinc/berlin-clock.js b/apps/berlinc/berlin-clock.js index 93b584f66..3950147b8 100644 --- a/apps/berlinc/berlin-clock.js +++ b/apps/berlinc/berlin-clock.js @@ -1,58 +1,97 @@ -// place your const, vars, functions or classes here -fields = [ 4 , 4 , 11 , 4 ]; -width = g.getWidth(); -height = g.getHeight(); -rowHeight = height/4; +// Berlin Clock see https://en.wikipedia.org/wiki/Mengenlehreuhr +// https://github.com/eska-muc/BangleApps +const fields = [4, 4, 11, 4]; +const offset = 20; +const width = g.getWidth() - 2 * offset; +const height = g.getHeight() - 2 * offset; +const rowHeight = height / 4; + +var show_date = false; +var show_time = false; +var yy = 0; + rowlights = []; +time_digit = []; function drawBerlinClock() { - var now = new Date(); - rowlights[0] = Math.floor(now.getHours() / 5); - rowlights[1] = now.getHours() % 5; - rowlights[2] = Math.floor(now.getMinutes() / 5); - rowlights[3] = now.getMinutes() % 5; + g.clear(); + var now = new Date(); + + // show date below the clock + if (show_date) { + var yr = now.getFullYear(); + var month = now.getMonth() + 1; + var day = now.getDate(); + var dateString = `${yr}-${month < 10 ? '0' : ''}${month}-${day < 10 ? '0' : ''}${day}`; + var strWidth = g.stringWidth(dateString); + g.setColor(1, 1, 1); + g.setFontAlign(-1,-1); + g.drawString(dateString, ( g.getWidth() - strWidth ) / 2, height + offset + 4); + } + + rowlights[0] = Math.floor(now.getHours() / 5); + rowlights[1] = now.getHours() % 5; + rowlights[2] = Math.floor(now.getMinutes() / 5); + rowlights[3] = now.getMinutes() % 5; - g.clear(); + time_digit[0] = Math.floor(now.getHours() / 10); + time_digit[1] = now.getHours() % 10; + time_digit[2] = Math.floor(now.getMinutes() / 10); + time_digit[3] = now.getMinutes() % 10; - g.drawRect(0,0,width,height); - for (row = 0 ; row < 4 ; row++) { - nfields = fields[row]; - boxWidth = width/nfields; + g.drawRect(offset, offset, width + offset, height + offset); + for (row = 0; row < 4; row++) { + nfields = fields[row]; + boxWidth = width / nfields; - for (col = 0 ; col < nfields ; col++) { - x1 = col*boxWidth; - y1 = row*rowHeight; - x2 = (col+1)*boxWidth; - y2 = (row+1)*rowHeight; + for (col = 0; col < nfields; col++) { + x1 = col * boxWidth + offset; + y1 = row * rowHeight + offset; + x2 = (col + 1) * boxWidth + offset; + y2 = (row + 1) * rowHeight + offset; - g.setColor(1,1,1); - g.drawRect(x1,y1,x2,y2); - if (col { g.clear(); if (on) { - Bangle.drawWidgets(); - // call your app function here - drawBerlinClock(); -}}); + Bangle.drawWidgets(); + // call your app function here + drawBerlinClock(); + } +}); // refesh every 15 sec setInterval(drawBerlinClock, 15E3); @@ -61,5 +100,9 @@ g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); drawBerlinClock(); +// Toggle date display, when BTN3 is pressed +setWatch(toggleTime,BTN1, { repeat : true, edge: "falling"}); +// Toggle date display, when BTN3 is pressed +setWatch(toggleDate,BTN3, { repeat : true, edge: "falling"}); // Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); diff --git a/apps/binclock/ChangeLog b/apps/binclock/ChangeLog new file mode 100644 index 000000000..2378e52f8 --- /dev/null +++ b/apps/binclock/ChangeLog @@ -0,0 +1,2 @@ +0.01: New App! +0.02: Fixed bug where screen didn't clear so incorrect time displayed. diff --git a/apps/binclock/app-icon.js b/apps/binclock/app-icon.js new file mode 100644 index 000000000..206c1ee42 --- /dev/null +++ b/apps/binclock/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkEIf4A/AH8AgP/iAECiIJCj/xAgURBoUAn8gAYMP//wAgIMBBwX//4gCAIUAgf/EIUfC5QEBC5MCI4gNCEIPyAgRGDLQMwBIwEJEAYEFAH7v3dQTpDAZ6cDdIYDPdQbpDAZ8QYgTpDAZ5IEAaYAeM4cRTYSuQiABBiQCBbckjmQzFmcggUzGJkBBoMDQgcSkMAAIIXOgL8CC6gvRL4b2CL4MwTIotJAAJfJiIiCC5RfHF4LdHC4wvGAwIvHL5UDYQIuBF44A/AH4A/AH4AbA")) diff --git a/apps/binclock/app.js b/apps/binclock/app.js new file mode 100644 index 000000000..7808dfe45 --- /dev/null +++ b/apps/binclock/app.js @@ -0,0 +1,178 @@ +// Load fonts +require("Font7x11Numeric7Seg").add(Graphics); +// position on screen +const X = 160, Y = 180; +var displayTime = 0; +var minuteLED = [0,0,0,0,0,0]; +var hourLED = [0,0,0,0,0]; +var prevMinute = [0,0,0,0,0,0]; +var prevHour = [0,0,0,0,0]; + + +function drawTime(d) { + // work out how to display the current time + var h = d.getHours(), m = d.getMinutes(); + var time = (" "+h).substr(-2) + ":" + ("0"+m).substr(-2); + // draw the current time (4x size 7 segment) + g.setFont("7x11Numeric7Seg",4); + g.setFontAlign(1,1); // align right bottom + g.drawString(time, X, Y, true /*clear background*/); + // draw the seconds (2x size 7 segment) + g.setFont("7x11Numeric7Seg",2); + g.drawString(("0"+d.getSeconds()).substr(-2), X+30, Y, true /*clear background*/); +} + +function updateHourArray(hours){ + + var j; + for(j=0;j 15){ + hourLED[0] = 1; + hours = hours - 16; + } + if(hours > 7){ + hourLED[1] = 1; + hours = hours - 8; + } + if(hours > 3){ + hourLED[2] = 1; + hours = hours - 4; + } + if(hours > 1){ + hourLED[3] = 1; + hours = hours - 2; + } + if(hours > 0){ + hourLED[4] = 1; + } + + return hourLED; + +} + +function updateMinuteArray(minutes){ + var j; + for(j=0;j 31){ + minuteLED[0] = 1; + minutes = minutes - 32; + } + if(minutes > 15){ + minuteLED[1] = 1; + minutes = minutes - 16; + } + if(minutes > 7){ + minuteLED[2] = 1; + minutes = minutes - 8; + } + if(minutes > 3){ + minuteLED[3] = 1; + minutes = minutes - 4; + } + if(minutes > 1){ + minuteLED[4] = 1; + minutes = minutes - 2; + } + if(minutes > 0){ + minuteLED[5] = 1; + } + + return minuteLED; + +} + +function draw(){ + + // work out how to display the current time + var d = new Date(); + var h = d.getHours(), m = d.getMinutes(); + + updateHourArray(h); + updateMinuteArray(m); + + var i; + //Draw hour circles + for(i=0; i{ + if (secondInterval) clearInterval(secondInterval); + secondInterval = undefined; + if (on) { + setInterval(draw, 1000); + draw(); // draw immediately + } +}); +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +setWatch(function() { + if(displayTime == 0){ + displayTime = 1; + } else{ + displayTime = 0; + } +}, BTN, {edge:"rising", debounce:50, repeat:true}); diff --git a/apps/binclock/app.png b/apps/binclock/app.png new file mode 100644 index 000000000..b22feb36b Binary files /dev/null and b/apps/binclock/app.png differ diff --git a/apps/blackjack/ChangeLog b/apps/blackjack/ChangeLog new file mode 100644 index 000000000..c941d90e5 --- /dev/null +++ b/apps/blackjack/ChangeLog @@ -0,0 +1 @@ +0.01: New game! BTN4- Hit card, BTN5- Stand \ No newline at end of file diff --git a/apps/blackjack/blackjack-icon.js b/apps/blackjack/blackjack-icon.js new file mode 100644 index 000000000..cb4d00cdd --- /dev/null +++ b/apps/blackjack/blackjack-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgIQNgfAAgU///wAgMH/4dBAoMMAQMQAQMIAQMYAQ4RCApcPwAFDgIwBAoQ4BAoMP8EHwfghk//AXBuEMv38n+AjEMvl8/4FDvoFBmEMvF994FBg04vgdBAoMAAot4AoNgAoPwAoZFBAongAoPggyIBAoPAg0HwAFDh4BBAoUeh0PwOAg08AocDv/+Ao3DAod//a3BAorBDAohRBgf+AocBAokApgCBhzSCWIkHVYgYCWIngYwQrB/gFDgF//AFDD4QAD8AFEAAIA=")) \ No newline at end of file diff --git a/apps/blackjack/blackjack.app.js b/apps/blackjack/blackjack.app.js new file mode 100644 index 000000000..ccc437e58 --- /dev/null +++ b/apps/blackjack/blackjack.app.js @@ -0,0 +1,191 @@ +const Clubs = { width : 48, height : 48, bpp : 1, + buffer : require("heatshrink").decompress(atob("ACcP+AFDn/8Aod//wFD///AgUBAoOAApsDAoPAAr4vLI4pTEgP8L4M/wEH/5rB//gh//x/x//wj//9/3//4n4iBAAIZBAol/Aof+Apv5z4FP+OPAo41BAoX8I4Pj45HBAoPD4YFBLIOD4JZBRAMD4CKC/AFBj59Cg/gQYYFXAB4=")) +}; + +const Spades = { width : 48, height : 48, bpp : 1, + buffer : require("heatshrink").decompress(atob("ABsBwAFDgfAAocH8AFDh/wAocf/AFDn/8Aod//wFD///FwYFBGAUDAoIwCg4FBGAUPAoIwCj4FBGAU/AoIwCv4FBGAQEBGAQuCGAQuCGAQFLHQQ8CAupHLL4prB+fPTgU/8fHVwbLLApbXFbpYFLdIoADA==")) +}; + +const Hearts = { width : 48, height : 48, bpp : 4, + buffer : require("heatshrink").decompress(atob("ADlVqtQBQ8FBYIKIrnMAAINGqoKC4okGCwYAB4AKDhgKE4oWKAAILDBQwYEBYwwDFwojFgoLHEgQ6H5hhCBZAkCBRAjLEgI6IC4YLIC5Y7BBZXBjgjVABYX/C8CnKABbXLABTvMC8sMC6fAC4KQURwIABRypgULwRgULwRIUCwhIRIwiRSRoZITCwx5POoowRCxAwNFxIwNCxQwLFxYwLCxgwJFxowJCxwwHFx4wHCyAwFFyIwFCyQwDFycAgoXBqAXTgFc4oWUJAJGUJARGVAEo")) +}; + +const Diamonds = { width : 48, height : 48, bpp : 4, + buffer : require("heatshrink").decompress(atob("AHUFC60M4AXV5nFIyvM5hGVC4JIUCwJIUIwRIUIwRIUCwZISIwgABqBGUJCQWFPKBGGJCFcC455OCw4wOOox5QIxB5NOpBIOFxZ5LCxYwKOpQwMIxh5KOxipLL6xgNR5QwMX5TvXPJZ1JJBpGLPJR1LJBZGNPJIWOJA5GOPJB1NJBIWQPIpGRJApGRPIoWSJAa8PJA5GTJAYWUJAJGVAAJGVAHo=")) +}; + + +var deck = []; +var player = {Hand:[]}; +var computer = {Hand:[]}; + +function createDeck() { + var suits = ["Spades", "Hearts", "Diamonds", "Clubs"]; + var values = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]; + + var dck = []; + for (var i = 0 ; i < values.length; i++) { + for(var x = 0; x < suits.length; x++) { + dck.push({ Value: values[i], Suit: suits[x] }); + } + } + return dck; +} + +function shuffle(a) { + var j, x, i; + for (i = a.length - 1; i > 0; i--) { + j = Math.floor(Math.random() * (i + 1)); + x = a[i]; + a[i] = a[j]; + a[j] = x; + } + return a; +} + +function EndGameMessdage(msg){ + g.drawString(msg, 155, 200); + setTimeout(function(){ + startGame(); + }, 2500); + +} + +function hitMe() { + player.Hand.push(deck.pop()); + renderOnScreen(1); + var playerWeight = calcWeight(player.Hand, 0); + + if(playerWeight == 21) + EndGameMessdage('WINNER'); + else if(playerWeight > 21) + EndGameMessdage('LOOSER'); +} + +function calcWeight(hand, hideCard) { + + if(hideCard === 1) { + if (hand[0].Value == "J" || hand[0].Value == "Q" || hand[0].Value == "K") + return "10 +"; + else if (hand[0].Value == "A") + return "11 +"; + else + return parseInt(hand[0].Value) +" +"; + } + else { + var weight = 0; + for(i=0; i 21 || bangleWeight < playerWeight) + EndGameMessdage('WINNER'); + else if(bangleWeight > playerWeight) + EndGameMessdage('LOOSER'); +} + +function renderOnScreen(HideCard) { + const fontName = "6x8"; + + g.clear(); // clear screen + g.reset(); // default draw styles + g.setFont(fontName, 1); + + g.drawString('RST', 220, 35); + g.drawString('Hit', 60, 230); + g.drawString('Stand', 165, 230); + + g.setFont(fontName, 3); + for(i=0; i { - devices.forEach(device =>{ - let deviceName = device.id.substring(0,17); + devices.forEach(device =>{ + let deviceName = device.id.substring(0,17); - if (device.name) { - deviceName = device.name; - } + if (device.name) { + deviceName = device.name; + } - menu[deviceName] = () => showDeviceInfo(device); - }); - showMainMenu(menu); + menu[deviceName] = () => showDeviceInfo(device); + }); + showMainMenu(menu); }, { active: true }); } diff --git a/apps/blescan/blescan.js b/apps/blescan/blescan.js index b3c1dc721..0a85113bd 100644 --- a/apps/blescan/blescan.js +++ b/apps/blescan/blescan.js @@ -22,22 +22,22 @@ function draw() { function scan() { NRF.findDevices(devices => { - for (let device of devices) { + for (let device of devices) { - // Only display devices that advertise a name + // Only display devices that advertise a name - if (device.name) { - // Remove no devices found message if it is present - if (menu[NODEVICE]) { - delete menu[NODEVICE]; - } - menu[device.name] = { - value : device.rssi, - onchange : () => {} - }; + if (device.name) { + // Remove no devices found message if it is present + if (menu[NODEVICE]) { + delete menu[NODEVICE]; } + menu[device.name] = { + value : device.rssi, + onchange : () => {} + }; } - draw(); + } + draw(); }, { active: true }); } diff --git a/apps/blobclk/ChangeLog b/apps/blobclk/ChangeLog index 1cfc59015..9715fc4ab 100644 --- a/apps/blobclk/ChangeLog +++ b/apps/blobclk/ChangeLog @@ -2,3 +2,4 @@ Only draw widgets after clearing screen - they update automatically Remove 'faceUp' check as it's automatic 0.03: Modified for use with new bootloader and firmware +0.04: Modified to account for changes in the behavior of Graphics.fillPoly diff --git a/apps/blobclk/clock-blob.js b/apps/blobclk/clock-blob.js index 48187d23c..76f10865f 100644 --- a/apps/blobclk/clock-blob.js +++ b/apps/blobclk/clock-blob.js @@ -1,103 +1,103 @@ const buf = Graphics.createArrayBuffer(144,200,1,{msb:true}); const NUMBERS = [ - [1,1,1,1,3,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1],//0 - [0,1,1,1,3,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1],//1 - [1,1,1,1,3,0,0,1,1,1,2,1,1,1,4,1,1,1,0,0,1,1,1,1,1],//2 - [1,1,1,1,3,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1],//3 - [1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,5,1,1,1,1,0,0,1,1,1],//4 - [1,1,1,1,1,1,1,1,0,0,5,1,1,1,3,0,0,1,1,1,1,1,1,1,1],//5 - [1,1,1,1,1,1,1,1,0,0,1,1,1,1,3,1,1,0,1,1,1,1,1,1,1],//6 - [1,1,1,1,3,0,0,1,1,1,0,2,1,1,1,0,1,1,1,0,0,1,1,1,0],//7 - [1,1,1,1,3,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1],//8 - [1,1,1,1,3,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1] //9 + [1,1,1,1,3,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1],//0 + [0,1,1,1,3,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1],//1 + [1,1,1,1,3,0,0,1,1,1,2,1,1,1,4,1,1,1,0,0,1,1,1,1,1],//2 + [1,1,1,1,3,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1],//3 + [1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,5,1,1,1,1,0,0,1,1,1],//4 + [1,1,1,1,1,1,1,1,0,0,5,1,1,1,3,0,0,1,1,1,1,1,1,1,1],//5 + [1,1,1,1,1,1,1,1,0,0,1,1,1,1,3,1,1,0,1,1,1,1,1,1,1],//6 + [1,1,1,1,3,0,0,1,1,1,0,2,1,1,1,0,1,1,1,0,0,1,1,1,0],//7 + [1,1,1,1,3,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1],//8 + [1,1,1,1,3,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1] //9 ]; let intervalRef = null; let digits = [-1,-1,-1,-1,-1,-1]; function flip() { - g.setColor(1,1,1); - g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer},55,26); + g.setColor(1,1,1); + g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer},55,26); } function drawPixel(ox,oy,x,y,r,p) { - let x1 = ox+x*(r*2+1); - let y1 = oy+y*(r*2+1); - let xmid = x1+r; - let ymid = y1+r; - let x2 = xmid+r; - let y2 = ymid+r; - if (p > 0) { - if (p > 1) { - buf.setColor(0,0,0); - buf.fillRect(x1,y1,x2,y2); - } - buf.setColor(1,1,1); - } else { - buf.setColor(0,0,0); - } - if (p < 2) { - buf.fillRect(x1,y1,x2,y2); - } else if (p === 2) { - buf.fillPoly([xmid,y1,x2,y1,x2,y2,x1,y2,x1,ymid]); - } else if (p === 3) { - buf.fillPoly([x1,y1,xmid,y1,x2,ymid,x2,y2,x1,y2]); - } else if (p === 4) { - buf.fillPoly([x1,y1,x2,y1,x2,ymid,xmid,y2,x1,y2]); - } else if (p === 5) { - buf.fillPoly([x1,y1,x2,y1,x2,y2,xmid,y2,x1,ymid]); + let x1 = ox+x*(r*2); + let y1 = oy+y*(r*2); + let xmid = x1+r; + let ymid = y1+r; + let x2 = xmid+r; + let y2 = ymid+r; + if (p > 0) { + if (p > 1) { + buf.setColor(0,0,0); + buf.fillPoly([x1,y1,x2,y1,x2,y2,x1,y2]); } + buf.setColor(1,1,1); + } else { + buf.setColor(0,0,0); + } + if (p < 2) { + buf.fillPoly([x1,y1,x2,y1,x2,y2,x1,y2]); + } else if (p === 2) { + buf.fillPoly([xmid,y1,x2,y1,x2,y2,x1,y2,x1,ymid]); + } else if (p === 3) { + buf.fillPoly([x1,y1,xmid,y1,x2,ymid,x2,y2,x1,y2]); + } else if (p === 4) { + buf.fillPoly([x1,y1,x2,y1,x2,ymid,xmid,y2,x1,y2]); + } else if (p === 5) { + buf.fillPoly([x1,y1,x2,y1,x2,y2,xmid,y2,x1,ymid]); + } } function redraw() { - let time = new Date(); - let hours = time.getHours(); - let mins = time.getMinutes(); - let secs = time.getSeconds(); + let time = new Date(); + let hours = time.getHours(); + let mins = time.getMinutes(); + let secs = time.getSeconds(); - let newDigits = [Math.floor(hours/10),hours%10,Math.floor(mins/10),mins%10,Math.floor(secs/10),secs%10]; + let newDigits = [Math.floor(hours/10),hours%10,Math.floor(mins/10),mins%10,Math.floor(secs/10),secs%10]; - for (var p = 0;p<25;p++) { - var px = p%5; - var py = Math.floor(p/5); - if (digits[0] === -1 || NUMBERS[newDigits[0]][p] !== NUMBERS[digits[0]][p] ) { - drawPixel(0,20,px,py,6,NUMBERS[newDigits[0]][p]); - } - if (digits[1] === -1 || NUMBERS[newDigits[1]][p] !== NUMBERS[digits[1]][p] ) { - drawPixel(78,20,px,py,6,NUMBERS[newDigits[1]][p]); - } - if (digits[2] === -1 || NUMBERS[newDigits[2]][p] !== NUMBERS[digits[2]][p] ) { - drawPixel(0,92,px,py,6,NUMBERS[newDigits[2]][p]); - } - if (digits[3] === -1 || NUMBERS[newDigits[3]][p] !== NUMBERS[digits[3]][p] ) { - drawPixel(78,92,px,py,6,NUMBERS[newDigits[3]][p]); - } - if (digits[4] === -1 || NUMBERS[newDigits[4]][p] !== NUMBERS[digits[4]][p] ) { - drawPixel(69,164,px,py,3,NUMBERS[newDigits[4]][p]); - } - if (digits[5] === -1 || NUMBERS[newDigits[5]][p] !== NUMBERS[digits[5]][p] ) { - drawPixel(108,164,px,py,3,NUMBERS[newDigits[5]][p]); - } + for (var p = 0;p<25;p++) { + var px = p%5; + var py = Math.floor(p/5); + if (digits[0] === -1 || NUMBERS[newDigits[0]][p] !== NUMBERS[digits[0]][p] ) { + drawPixel(0,20,px,py,6,NUMBERS[newDigits[0]][p]); } - digits = newDigits; - flip(); + if (digits[1] === -1 || NUMBERS[newDigits[1]][p] !== NUMBERS[digits[1]][p] ) { + drawPixel(78,20,px,py,6,NUMBERS[newDigits[1]][p]); + } + if (digits[2] === -1 || NUMBERS[newDigits[2]][p] !== NUMBERS[digits[2]][p] ) { + drawPixel(0,92,px,py,6,NUMBERS[newDigits[2]][p]); + } + if (digits[3] === -1 || NUMBERS[newDigits[3]][p] !== NUMBERS[digits[3]][p] ) { + drawPixel(78,92,px,py,6,NUMBERS[newDigits[3]][p]); + } + if (digits[4] === -1 || NUMBERS[newDigits[4]][p] !== NUMBERS[digits[4]][p] ) { + drawPixel(69,164,px,py,3,NUMBERS[newDigits[4]][p]); + } + if (digits[5] === -1 || NUMBERS[newDigits[5]][p] !== NUMBERS[digits[5]][p] ) { + drawPixel(108,164,px,py,3,NUMBERS[newDigits[5]][p]); + } + } + digits = newDigits; + flip(); } function clearTimers() { - if(intervalRef) { - clearInterval(intervalRef); - intervalRef = undefined; - } + if(intervalRef) { + clearInterval(intervalRef); + intervalRef = undefined; + } } function startTimers() { - g.clear(); - Bangle.drawWidgets(); - intervalRef = setInterval(redraw,1000); - redraw(); + g.clear(); + Bangle.drawWidgets(); + intervalRef = setInterval(redraw,1000); + redraw(); } Bangle.loadWidgets(); startTimers(); Bangle.on('lcdPower',function(on) { - if (on) { - startTimers(); - } else { - clearTimers(); - } + if (on) { + startTimers(); + } else { + clearTimers(); + } }); // Show launcher when middle button pressed setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); diff --git a/apps/boldclk/ChangeLog b/apps/boldclk/ChangeLog index 7819dbe2a..0d02bf644 100644 --- a/apps/boldclk/ChangeLog +++ b/apps/boldclk/ChangeLog @@ -1 +1,2 @@ 0.02: Modified for use with new bootloader and firmware +0.03: Tweak for more efficient rendering, and firmware 2v06 diff --git a/apps/boldclk/bold_clock.js b/apps/boldclk/bold_clock.js index 9ef95bb2e..b7eaa8968 100644 --- a/apps/boldclk/bold_clock.js +++ b/apps/boldclk/bold_clock.js @@ -1,12 +1,12 @@ var hour_hand = { - width : 61, height : 8, bpp : 1, - transparent : 0, - buffer : E.toArrayBuffer(atob("/////////////////////////////////////////////////////////////////////////////////w==")) + width : 61, height : 8, bpp : 1, + transparent : 0, + buffer : E.toArrayBuffer(atob("/////////////////////////////////////////////////////////////////////////////////w==")) }; var minute_hand = { - width : 110, height : 4, bpp : 1, - transparent : 0, - buffer : E.toArrayBuffer(atob("/////////////////////////////////////////////////////////////////////////w==")) + width : 110, height : 4, bpp : 1, + transparent : 0, + buffer : E.toArrayBuffer(atob("/////////////////////////////////////////////////////////////////////////w==")) }; //g.fillRect(0,24,239,239); // Apps area @@ -16,125 +16,125 @@ const clock_center = {x:Math.floor((240-1)/2), y:24+Math.floor((239-24)/2)}; // ={ x: 119, y: 131 } const radius = Math.floor((239-24+1)/2); // =108 -let tick0 = Graphics.createArrayBuffer(30,8,1); +let tick0 = Graphics.createArrayBuffer(30,8,1,{msb:true}); tick0.fillRect(0,0,tick0.getWidth()-1, tick0.getHeight()-1); -let tick5 = Graphics.createArrayBuffer(20,6,1); +let tick5 = Graphics.createArrayBuffer(20,6,1,{msb:true}); tick5.fillRect(0,0,tick5.getWidth()-1, tick5.getHeight()-1); -let tick1 = Graphics.createArrayBuffer(8,4,1); +let tick1 = Graphics.createArrayBuffer(8,4,1,{msb:true}); tick1.fillRect(0,0,tick1.getWidth()-1, tick1.getHeight()-1); function big_wheel_x(angle){ - return clock_center.x + radius * Math.cos(angle*p180); + return clock_center.x + radius * Math.cos(angle*p180); } function big_wheel_y(angle){ - return clock_center.y + radius * Math.sin(angle*p180); + return clock_center.y + radius * Math.sin(angle*p180); } function rotate_around_x(center_x, angle, tick){ - return center_x + Math.cos(angle*p180) * tick.getWidth()/2; + return center_x + Math.cos(angle*p180) * tick.getWidth()/2; } function rotate_around_y(center_y, angle, tick){ - return center_y + Math.sin(angle*p180) * tick.getWidth()/2; + return center_y + Math.sin(angle*p180) * tick.getWidth()/2; } function hour_pos_x(angle){ - return clock_center.x + Math.cos(angle*p180) * hour_hand.width/2; + return clock_center.x + Math.cos(angle*p180) * hour_hand.width/2; } function hour_pos_y(angle){ - return clock_center.y + Math.sin(angle*p180) * hour_hand.width/2; + return clock_center.y + Math.sin(angle*p180) * hour_hand.width/2; } function minute_pos_x(angle){ - return clock_center.x + Math.cos(angle*p180) * minute_hand.width/2; + return clock_center.x + Math.cos(angle*p180) * minute_hand.width/2; } function minute_pos_y(angle){ - return clock_center.y + Math.sin(angle*p180) * minute_hand.width/2; + return clock_center.y + Math.sin(angle*p180) * minute_hand.width/2; } function minute_angle(date){ - //let minutes = date.getMinutes() + date.getSeconds()/60; - let minutes = date.getMinutes(); - return 6*minutes - 90; + //let minutes = date.getMinutes() + date.getSeconds()/60; + let minutes = date.getMinutes(); + return 6*minutes - 90; } function hour_angle(date){ - let hours= date.getHours() + date.getMinutes()/60; - return 30*hours - 90; + let hours= date.getHours() + date.getMinutes()/60; + return 30*hours - 90; } function draw_clock(){ - //console.log("draw_clock"); - let date = new Date(); - //g.clear(); - g.setBgColor(0,0,0); - g.setColor(0,0,0); - g.fillRect(0,24,239,239); // clear app area - g.setColor(1,1,1); + //console.log("draw_clock"); + let date = new Date(); + //g.clear(); + g.setBgColor(0,0,0); + g.setColor(0,0,0); + g.fillRect(0,24,239,239); // clear app area + g.setColor(1,1,1); - // draw cross lines for testing - // g.setColor(1,0,0); - // g.drawLine(clock_center.x - radius, clock_center.y, clock_center.x + radius, clock_center.y); - // g.drawLine(clock_center.x, clock_center.y - radius, clock_center.x, clock_center.y + radius); + // draw cross lines for testing + // g.setColor(1,0,0); + // g.drawLine(clock_center.x - radius, clock_center.y, clock_center.x + radius, clock_center.y); + // g.drawLine(clock_center.x, clock_center.y - radius, clock_center.x, clock_center.y + radius); - g.setColor(1,1,1); - let ticks = [0, 90, 180, 270]; - ticks.forEach((item)=>{ - let agl = item+180; - g.drawImage(tick0.asImage(), rotate_around_x(big_wheel_x(item), agl, tick0), rotate_around_y(big_wheel_y(item), agl, tick0), {rotate:agl*p180}); - }); - ticks = [30, 60, 120, 150, 210, 240, 300, 330]; - ticks.forEach((item)=>{ - let agl = item+180; - g.drawImage(tick5.asImage(), rotate_around_x(big_wheel_x(item), agl, tick5), rotate_around_y(big_wheel_y(item), agl, tick5), {rotate:agl*p180}); - }); + g.setColor(1,1,1); + let ticks = [0, 90, 180, 270]; + ticks.forEach((item)=>{ + let agl = item+180; + g.drawImage(tick0.asImage(), rotate_around_x(big_wheel_x(item), agl, tick0), rotate_around_y(big_wheel_y(item), agl, tick0), {rotate:agl*p180}); + }); + ticks = [30, 60, 120, 150, 210, 240, 300, 330]; + ticks.forEach((item)=>{ + let agl = item+180; + g.drawImage(tick5.asImage(), rotate_around_x(big_wheel_x(item), agl, tick5), rotate_around_y(big_wheel_y(item), agl, tick5), {rotate:agl*p180}); + }); - let hour_agl = hour_angle(date); - let minute_agl = minute_angle(date); - g.drawImage(hour_hand, hour_pos_x(hour_agl), hour_pos_y(hour_agl), {rotate:hour_agl*p180}); // - g.drawImage(minute_hand, minute_pos_x(minute_agl), minute_pos_y(minute_agl), {rotate:minute_agl*p180}); // - g.setColor(1,1,1); - g.fillCircle(clock_center.x, clock_center.y, 6); - g.setColor(0,0,0); - g.fillCircle(clock_center.x, clock_center.y, 3); + let hour_agl = hour_angle(date); + let minute_agl = minute_angle(date); + g.drawImage(hour_hand, hour_pos_x(hour_agl), hour_pos_y(hour_agl), {rotate:hour_agl*p180}); // + g.drawImage(minute_hand, minute_pos_x(minute_agl), minute_pos_y(minute_agl), {rotate:minute_agl*p180}); // + g.setColor(1,1,1); + g.fillCircle(clock_center.x, clock_center.y, 6); + g.setColor(0,0,0); + g.fillCircle(clock_center.x, clock_center.y, 3); - // draw minute ticks. Takes long time to draw! - g.setColor(1,1,1); - for (var i=0; i<60; i++){ - let agl = i*6+180; - g.drawImage(tick1.asImage(), rotate_around_x(big_wheel_x(i*6), agl, tick1), rotate_around_y(big_wheel_y(i*6), agl, tick1), {rotate:agl*p180}); - } + // draw minute ticks. Takes long time to draw! + g.setColor(1,1,1); + for (var i=0; i<60; i++){ + let agl = i*6+180; + g.drawImage(tick1.asImage(), rotate_around_x(big_wheel_x(i*6), agl, tick1), rotate_around_y(big_wheel_y(i*6), agl, tick1), {rotate:agl*p180}); + } - g.flip(); - //console.log(date); + g.flip(); + //console.log(date); } function clearTimers(){ - //console.log("clearTimers"); - if(intervalRef) { - clearInterval(intervalRef); - intervalRef = null; - //console.log("interval is cleared"); - } + //console.log("clearTimers"); + if(intervalRef) { + clearInterval(intervalRef); + intervalRef = null; + //console.log("interval is cleared"); + } } function startTimers(){ - //console.log("startTimers"); - if(intervalRef) clearTimers(); - intervalRef = setInterval(draw_clock, 60*1000); - //console.log("interval is set"); - draw_clock(); + //console.log("startTimers"); + if(intervalRef) clearTimers(); + intervalRef = setInterval(draw_clock, 60*1000); + //console.log("interval is set"); + draw_clock(); } Bangle.on('lcdPower', (on) => { - if (on) { - //console.log("lcdPower: on"); - Bangle.drawWidgets(); - startTimers(); - } else { - //console.log("lcdPower: off"); - clearTimers(); - } + if (on) { + //console.log("lcdPower: on"); + Bangle.drawWidgets(); + startTimers(); + } else { + //console.log("lcdPower: off"); + clearTimers(); + } }); Bangle.on('faceUp',function(up){ - //console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn()); - if (up && !Bangle.isLCDOn()) { - //console.log("faceUp and LCD off"); - clearTimers(); - Bangle.setLCDPower(true); - } + //console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn()); + if (up && !Bangle.isLCDOn()) { + //console.log("faceUp and LCD off"); + clearTimers(); + Bangle.setLCDPower(true); + } }); g.clear(); diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 7ab79a5a5..d2f68fd0e 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -13,3 +13,10 @@ 0.13: Now automatically load *.boot.js at startup Move alarm code into alarm.boot.js 0.14: Move welcome loaders to *.boot.js +0.15: Added BLE HID option for Joystick and bare Keyboard +0.16: Detect out of memory errors and draw them onto the bottom of the screen in red +0.17: Don't modify beep/buzz behaviour if firmware does it automatically +0.18: Fix 'GPS time' checks for western hemisphere +0.19: Tweaks to simplify code and lower memory usage +0.20: Allow Gadgetbridge to work even with programmable:off +0.21: Handle echo off char from Gadgetbridge app when programmable:off (fix #558) diff --git a/apps/boot/boot0.js b/apps/boot/boot0.js index dd3b3a9ba..630252dea 100644 --- a/apps/boot/boot0.js +++ b/apps/boot/boot0.js @@ -4,13 +4,28 @@ E.setFlags({pretokenise:1}); var s = require('Storage').readJSON('setting.json',1)||{}; if (s.ble!==false) { if (s.HID) { // Human interface device - Bangle.HID = E.toUint8Array(atob("BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA==")); + if (s.HID=="joy") Bangle.HID = E.toUint8Array(atob("BQEJBKEBCQGhAAUJGQEpBRUAJQGVBXUBgQKVA3UBgQMFAQkwCTEVgSV/dQiVAoECwMA=")); + else if (s.HID=="kb") Bangle.HID = E.toUint8Array(atob("BQEJBqEBBQcZ4CnnFQAlAXUBlQiBApUBdQiBAZUFdQEFCBkBKQWRApUBdQORAZUGdQgVACVzBQcZAClzgQAJBRUAJv8AdQiVArECwA==")); + else /*kbmedia*/Bangle.HID = E.toUint8Array(atob("BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA==")); NRF.setServices({}, {uart:true, hid:Bangle.HID}); } } if (s.blerepl===false) { // If not programmable, force terminal off Bluetooth if (s.log) Terminal.setConsole(true); // if showing debug, force REPL onto terminal else E.setConsole(null,{force:true}); // on new (2v05+) firmware we have E.setConsole which allows a 'null' console + /* If not programmable add our own handler for Bluetooth data + to allow Gadgetbridge commands to be received*/ + Bluetooth.line=""; + Bluetooth.on('data',function(d) { + var l = (Bluetooth.line + d).split("\n"); + Bluetooth.line = l.pop(); + l.forEach(n=>Bluetooth.emit("line",n)); + }); + Bluetooth.on('line',function(l) { + if (l.startsWith('\x10')) l=l.slice(1); + if (l.startsWith('GB({') && l.endsWith('})') && global.GB) + try { global.GB(JSON.parse(l.slice(3,-1))); } catch(e) {} + }); } else { if (s.log && !NRF.getSecurityStatus().connected) Terminal.setConsole(); // if showing debug, put REPL on terminal (until connection) else Bluetooth.setConsole(true); // else if no debug, force REPL to Bluetooth @@ -19,27 +34,35 @@ if (s.blerepl===false) { // If not programmable, force terminal off Bluetooth // Don't disconnect if something is already connected to us if (s.ble===false && !NRF.getSecurityStatus().connected) NRF.sleep(); // Set time, vibrate, beep, etc -if (!s.vibrate) Bangle.buzz=Promise.resolve; -if (s.beep===false) Bangle.beep=Promise.resolve; -else if (s.beep=="vib") Bangle.beep = function (time, freq) { - return new Promise(function(resolve) { - if ((0|freq)<=0) freq=4000; - if ((0|time)<=0) time=200; - if (time>5000) time=5000; - analogWrite(D13,0.1,{freq:freq}); - setTimeout(function() { - digitalWrite(D13,0); - resolve(); - }, time); - }); -}; +if (!Bangle.F_BEEPSET) { + if (!s.vibrate) Bangle.buzz=Promise.resolve; + if (s.beep===false) Bangle.beep=Promise.resolve; + else if (s.beep=="vib") Bangle.beep = function (time, freq) { + return new Promise(function(resolve) { + if ((0|freq)<=0) freq=4000; + if ((0|time)<=0) time=200; + if (time>5000) time=5000; + analogWrite(D13,0.1,{freq:freq}); + setTimeout(function() { + digitalWrite(D13,0); + resolve(); + }, time); + }); + }; +} Bangle.setLCDTimeout(s.timeout); if (!s.timeout) Bangle.setLCDPower(1); E.setTimeZone(s.timezone); delete s; +// Draw out of memory errors onto the screen +E.on('errorFlag', function(errorFlags) { + g.reset(1).setColor("#ff0000").setFont("6x8").setFontAlign(0,1).drawString(errorFlags,g.getWidth()/2,g.getHeight()-1).flip(); + print("Interpreter error:", errorFlags); + E.getErrorFlags(); // clear flags so we get called next time +}); // stop users doing bad things! global.save = function() { throw new Error("You can't use save() on Bangle.js without overwriting the bootloader!"); } // Load *.boot.js files -require('Storage').list(/\.boot\.js/).map(bootFile=>{ +require('Storage').list(/\.boot\.js/).forEach(bootFile=>{ eval(require('Storage').read(bootFile)); }); diff --git a/apps/boot/bootloader.js b/apps/boot/bootloader.js index c16984f10..df3718dcc 100644 --- a/apps/boot/bootloader.js +++ b/apps/boot/bootloader.js @@ -1,30 +1,35 @@ // This runs after a 'fresh' boot -var settings=require("Storage").readJSON('setting.json',1)||{}; -// load clock if specified -var clockApp = settings.clock; -if (clockApp) clockApp = require("Storage").read(clockApp) +var clockApp=(require("Storage").readJSON("setting.json",1)||{}).clock; +if (clockApp) clockApp = require("Storage").read(clockApp); if (!clockApp) { - var clockApps = require("Storage").list(/\.info$/).map(app=>require("Storage").readJSON(app,1)||{}).filter(app=>app.type=="clock").sort((a, b) => a.sortorder - b.sortorder); - if (clockApps && clockApps.length > 0) - clockApp = require("Storage").read(clockApps[0].src); - delete clockApps; + clockApp = require("Storage").list(/\.info$/) + .map(file => { + const app = require("Storage").readJSON(file,1); + if (app && app.type == "clock") { + return app; + } + }) + .filter(x=>x) + .sort((a, b) => a.sortorder - b.sortorder)[0]; + if (clockApp) + clockApp = require("Storage").read(clockApp.src); } if (!clockApp) clockApp=`E.showMessage("No Clock Found"); setWatch(() => { Bangle.showLauncher(); }, BTN2, {repeat:false,edge:"falling"});) `; -delete settings; // check to see if our clock is wrong - if it is use GPS time -if ((new Date()).getFullYear()==1970) { +if ((new Date()).getFullYear()<2000) { E.showMessage("Searching for\nGPS time"); - Bangle.on('GPS',function cb(g) { + Bangle.on("GPS",function cb(g) { Bangle.setGPSPower(0); Bangle.removeListener("GPS",cb); if (!g.time || (g.time.getFullYear()<2000) || - (g.time.getFullYear()==2250)) { + (g.time.getFullYear()>2200)) { // GPS receiver's time not set - just boot clock anyway - eval(clockApp);delete clockApp; + eval(clockApp); + delete clockApp; return; } // We have a GPS time. Set time and reboot (to load alarms properly) diff --git a/apps/boot/hid_info.txt b/apps/boot/hid_info.txt new file mode 100644 index 000000000..873b50f63 --- /dev/null +++ b/apps/boot/hid_info.txt @@ -0,0 +1,88 @@ + +## Joystick: + +https://github.com/espruino/BangleApps/issues/349#issuecomment-620231524 + +``` +0x05, 0x01, // Usage Page (Generic Desktop) +0x09, 0x04, // Usage (Joystick) +0xA1, 0x01, // Collection (Application) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + // Buttons + 0x05, 0x09, // Usage Page (Buttons) + 0x19, 0x01, // Usage Minimum (1) + 0x29, 0x05, // Usage Maximum (5) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x95, 0x05, // Report Count (5) + 0x75, 0x01, // Report Size (1) + 0x81, 0x02, // Input (Data, Variable, Absolute) + + // padding bits + 0x95, 0x03, // Report Count (3) + 0x75, 0x01, // Report Size (1) + 0x81, 0x03, // Input (Constant) + + // Stick + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7f, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x95, 0x02, // Report Count (2) + 0x81, 0x02, // Input (Data, Variable, Absolute) + 0xC0, // End Collection (Physical) +0xC0 // End Collection (Application) +``` + +## Keyboard + +http://www.espruino.com/BLE+Keyboard + +``` +0x05, 0x01, // Usage Page (Generic Desktop) +0x09, 0x06, // Usage (Keyboard) +0xA1, 0x01, // Collection (Application) +0x05, 0x07, // Usage Page (Key Codes) +0x19, 0xe0, // Usage Minimum (224) +0x29, 0xe7, // Usage Maximum (231) +0x15, 0x00, // Logical Minimum (0) +0x25, 0x01, // Logical Maximum (1) +0x75, 0x01, // Report Size (1) +0x95, 0x08, // Report Count (8) +0x81, 0x02, // Input (Data, Variable, Absolute) + +0x95, 0x01, // Report Count (1) +0x75, 0x08, // Report Size (8) +0x81, 0x01, // Input (Constant) reserved byte(1) + +0x95, 0x05, // Report Count (5) +0x75, 0x01, // Report Size (1) +0x05, 0x08, // Usage Page (Page# for LEDs) +0x19, 0x01, // Usage Minimum (1) +0x29, 0x05, // Usage Maximum (5) +0x91, 0x02, // Output (Data, Variable, Absolute), Led report +0x95, 0x01, // Report Count (1) +0x75, 0x03, // Report Size (3) +0x91, 0x01, // Output (Data, Variable, Absolute), Led report padding + +0x95, 0x06, // Report Count (6) +0x75, 0x08, // Report Size (8) +0x15, 0x00, // Logical Minimum (0) +0x25, 0x73, // Logical Maximum (115 - include F13, etc) +0x05, 0x07, // Usage Page (Key codes) +0x19, 0x00, // Usage Minimum (0) +0x29, 0x73, // Usage Maximum (115 - include F13, etc) +0x81, 0x00, // Input (Data, Array) Key array(6 bytes) + +0x09, 0x05, // Usage (Vendor Defined) +0x15, 0x00, // Logical Minimum (0) +0x26, 0xFF, 0x00, // Logical Maximum (255) +0x75, 0x08, // Report Count (2) +0x95, 0x02, // Report Size (8 bit) +0xB1, 0x02, // Feature (Data, Variable, Absolute) + +0xC0 // End Collection (Application) +``` diff --git a/apps/bootgattbat/ChangeLog b/apps/bootgattbat/ChangeLog new file mode 100644 index 000000000..2a37193a3 --- /dev/null +++ b/apps/bootgattbat/ChangeLog @@ -0,0 +1 @@ +0.01: Initial release. diff --git a/apps/bootgattbat/README.md b/apps/bootgattbat/README.md new file mode 100644 index 000000000..3e559c0a5 --- /dev/null +++ b/apps/bootgattbat/README.md @@ -0,0 +1,16 @@ +# BLE GATT Battery Service + +Adds the GATT Battery Service to advertise the percentage of battery currently remaining over Bluetooth. + +## Usage + +This boot code runs in the background and has no user interface. + +## Requests + +If you have any suggestions or ideas please post in [this forum thread](http://forum.espruino.com/conversations/351959/), +or [@jjok](https://github.com/jjok) in your Github issue. + +## Creator + +[Jonathan Jefferies](https://github.com/jjok) diff --git a/apps/bootgattbat/bluetooth.png b/apps/bootgattbat/bluetooth.png new file mode 100644 index 000000000..1a884a62c Binary files /dev/null and b/apps/bootgattbat/bluetooth.png differ diff --git a/apps/bootgattbat/boot.js b/apps/bootgattbat/boot.js new file mode 100644 index 000000000..d67b766b5 --- /dev/null +++ b/apps/bootgattbat/boot.js @@ -0,0 +1,10 @@ +(() => { + function advertiseBattery() { + Bangle.bleAdvert[0x180F] = [E.getBattery()]; + NRF.setAdvertising(Bangle.bleAdvert); + } + + if (!Bangle.bleAdvert) Bangle.bleAdvert = {}; + setInterval(advertiseBattery, 60 * 1000); + advertiseBattery(); +})(); diff --git a/apps/buffgym/.eslintrc.json b/apps/buffgym/.eslintrc.json new file mode 100644 index 000000000..aaae0a0cb --- /dev/null +++ b/apps/buffgym/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "env": { + "browser": true, + "commonjs": true, + "es6": true + }, + "extends": "eslint:recommended", + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 2018 + }, + "rules": { + "indent": [ + "error", + 2, + { "SwitchCase": 1 } + ], + "linebreak-style": [ + "error", + "windows" + ], + "quotes": [ + "error", + "double" + ] + /*, + "semi": [ + "error", + "always" + ]*/ + } +} \ No newline at end of file diff --git a/apps/buffgym/ChangeLog b/apps/buffgym/ChangeLog new file mode 100644 index 000000000..6efdd865a --- /dev/null +++ b/apps/buffgym/ChangeLog @@ -0,0 +1,2 @@ +0.01: Create BuffGym app +0.02: Add web interface for personalising workout diff --git a/apps/buffgym/README.md b/apps/buffgym/README.md new file mode 100644 index 000000000..bcadf22c4 --- /dev/null +++ b/apps/buffgym/README.md @@ -0,0 +1,60 @@ +# BuffGym + +This gym training assistant trains you on the famous [Stronglifts 5x5 workout](https://stronglifts.com/5x5) program. + +## Configuration + +### Setting your start weight values + +You will want to set your own starting weight values for your 5x5 training program. To do this is easy! After installing this app, go to the BangleJS app store, connect to your watch, and navigate to the `My Apps` tab. In there you will find this app in the list, and an icon (a down arrow) to the right of the app title. Click that icon to reveal a configuration page. Enter your weights and other details, and click upload. That is it, you are now ready to train! + +## Usage + +### Start screen + +When you start the app it will wait on a splash screen until you are ready to start the work out. Press any of the buttons to start + +![](buffgym-scrn1.png) + +### Workouts menu + +You are then presented with the workouts menu, use BTN1 to move up the list, and BTN3 to move down the list. Once you have made your selection, press BTN2 to select the workout. + +![](buffgym-scrn2.png) + +### Recording your training + +You will now begin moving through the exercises in the workout. You will see the exercise information on the display. + +![](buffgym-scrn3.png) + +1. At the top is the exercise name, e.g 'Squats' +2. Next is the weight you must train +3. In the center is where you record the number of *reps* you completed (more on that shortly) +4. Below the *reps* value, is the target reps you must try to reach. +5. Below the target reps is the current set you are training, out of the total sets for the exercise. +6. The *reps* value is used to store what you achieved for the current set, you enter this after you have trained on your current set. To alter this value, use BTN1 to increase the value (it will stop at the maximum required reps) and BTN3 to decreas the value to a minimum of 0 (this is the default value). Pressing BTN2 will confirm your reps + +### Rest timers + +You will then be presented with a rest timer screen, it counts down and automatically moves to the next exercise when it reaches 0. You can cancel the timer early if you wish by pressing BTN2. If it is the last set of an exercise, you don't need to rest, so it lets you know you have completed all the sets in the exercise and can start the next exercise. + +![](buffgym-scrn4.png) +![](buffgym-scrn5.png) + +### Workout completed + +Once all exercises are done, you are presented with a pat-on-the-back screen to tell you how awesome you are. + +![](buffgym-scrn6.png) + +## Features + +* If you successfully complete all reps and sets for an exercise, it will automatically update your weights for next time +* Has a neat rest timer to make sure you are training optimally +* Doesn't require a mobile phone, most 'smart watches' are just a visual presentation of the mobile phone app, this runs purley on the watch. So why not leave your phone and its distractions out of the gym! +* Clear and simple user interface + +## Created by + +[Paul Cockrell](https://github.com/paulcockrell) April 2020. diff --git a/apps/buffgym/buffgym-exercise.js b/apps/buffgym/buffgym-exercise.js new file mode 100644 index 000000000..103ff99b7 --- /dev/null +++ b/apps/buffgym/buffgym-exercise.js @@ -0,0 +1,153 @@ +exports = class Exercise { + constructor(params) { + this.completed = false; + this.sets = []; + this.title = params.title; + this.weight = params.weight; + this.weightIncrement = params.weightIncrement; + this.unit = params.unit; + this.restPeriod = params.restPeriod; + this._originalRestPeriod = params.restPeriod; + this._restTimeout = null; + this._restInterval = null; + this._state = null; + } + + get humanTitle() { + return `${this.title} ${this.weight}${this.unit}`; + } + + get subTitle() { + const totalSets = this.sets.length; + const uncompletedSets = this.sets.filter((set) => !set.isCompleted()).length; + const currentSet = (totalSets - uncompletedSets) + 1; + return `Set ${currentSet} of ${totalSets}`; + } + + decRestPeriod() { + this.restPeriod--; + } + + addSet(set) { + this.sets.push(set); + } + + currentSet() { + return this.sets.filter(set => !set.isCompleted())[0]; + } + + isLastSet() { + return this.sets.filter(set => !set.isCompleted()).length === 1; + } + + isCompleted() { + return !!this.completed; + } + + canSetCompleted() { + return this.sets.filter(set => set.isCompleted()).length === this.sets.length; + } + + setCompleted() { + if (!this.canSetCompleted()) throw "All sets must be completed"; + if (this.canProgress()) this.weight += this.weightIncrement; + this.completed = true; + } + + canProgress() { + let completedRepsTotalSum = 0; + let targetRepsTotalSum = 0; + this.sets.forEach(set => completedRepsTotalSum += set.reps); + this.sets.forEach(set => targetRepsTotalSum += set.maxReps); + + return (targetRepsTotalSum - completedRepsTotalSum) === 0; + } + + startRestTimer(workout) { + this._restTimeout = setTimeout(() => { + this.next(workout); + }, 1000 * this.restPeriod); + + this._restInterval = setInterval(() => { + this.decRestPeriod(); + + if (this.restPeriod < 0) { + this.resetRestTimer(); + this.next(); + + return; + } + + workout.emit("redraw"); + }, 1000 ); + } + + resetRestTimer() { + clearTimeout(this._restTimeout); + clearInterval(this._restInterval); + this._restTimeout = null; + this._restInterval = null; + this.restPeriod = this._originalRestPeriod; + } + + isRestTimerRunning() { + return this._restTimeout != null; + } + + setupStartedButtons(workout) { + clearWatch(); + + setWatch(() => { + this.currentSet().incReps(); + workout.emit("redraw"); + }, BTN1, {repeat: true}); + + setWatch(workout.next.bind(workout), BTN2, {repeat: false}); + + setWatch(() => { + this.currentSet().decReps(); + workout.emit("redraw"); + }, BTN3, {repeat: true}); + } + + setupRestingButtons(workout) { + clearWatch(); + setWatch(workout.next.bind(workout), BTN2, {repeat: false}); + } + + next(workout) { + const STARTED = 1; + const RESTING = 2; + const COMPLETED = 3; + + switch(this._state) { + case null: + this._state = STARTED; + this.setupStartedButtons(workout); + break; + case STARTED: + this._state = RESTING; + this.startRestTimer(workout); + this.setupRestingButtons(workout); + break; + case RESTING: + this.resetRestTimer(); + this.currentSet().setCompleted(); + + if (this.canSetCompleted()) { + this._state = COMPLETED; + this.setCompleted(); + } else { + this._state = null; + } + // As we are changing state and require it to be reprocessed + // invoke the next step of workout + workout.next(); + break; + default: + throw "Exercise: Attempting to move to an unknown state"; + } + + workout.emit("redraw"); + } +}; \ No newline at end of file diff --git a/apps/buffgym/buffgym-icon.js b/apps/buffgym/buffgym-icon.js new file mode 100644 index 000000000..9938c9030 --- /dev/null +++ b/apps/buffgym/buffgym-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+ACPI5AUSADAtB5vNGFQtBAIfNF95hoF4wwoF5AwmF5BhmXYbAEF/6QbF1QwIF04qB54ADAwIwoF4oRKBoIvsB4gvZ58kkgCDFxoxaF5wuHGDQcMF5IwXDZwLDGDmlDIWlkgJDSwIABCRAwPDQohCFgIABDQIOCFwYABr4RCCQIvQDYguEAAwtFF5owJDZAvHFw4vFOYQvKFAowMBxIvFMQwvPAB4wFUQ4vJGDYvUGC4vNdgyuEGDIsNFwYwGNAgAPExAvMGIdfTIovfTpYvrfRCOkZ44ugF44NGF05gUFyQvKGIoueGKIufGJ4uhG5oupGItfr4vvAAgvlGAQvt/wrEF9oEGF841IF9QGHX0oGIAD8kAAYJOFzwEBBQoMFACA=")) diff --git a/apps/buffgym/buffgym-scrn1.png b/apps/buffgym/buffgym-scrn1.png new file mode 100755 index 000000000..07b79386f Binary files /dev/null and b/apps/buffgym/buffgym-scrn1.png differ diff --git a/apps/buffgym/buffgym-scrn2.png b/apps/buffgym/buffgym-scrn2.png new file mode 100755 index 000000000..ec70fb791 Binary files /dev/null and b/apps/buffgym/buffgym-scrn2.png differ diff --git a/apps/buffgym/buffgym-scrn3.png b/apps/buffgym/buffgym-scrn3.png new file mode 100755 index 000000000..0888fc507 Binary files /dev/null and b/apps/buffgym/buffgym-scrn3.png differ diff --git a/apps/buffgym/buffgym-scrn4.png b/apps/buffgym/buffgym-scrn4.png new file mode 100755 index 000000000..3078d25dc Binary files /dev/null and b/apps/buffgym/buffgym-scrn4.png differ diff --git a/apps/buffgym/buffgym-scrn5.png b/apps/buffgym/buffgym-scrn5.png new file mode 100755 index 000000000..b34a5b124 Binary files /dev/null and b/apps/buffgym/buffgym-scrn5.png differ diff --git a/apps/buffgym/buffgym-scrn6.png b/apps/buffgym/buffgym-scrn6.png new file mode 100755 index 000000000..563426ad3 Binary files /dev/null and b/apps/buffgym/buffgym-scrn6.png differ diff --git a/apps/buffgym/buffgym-set.js b/apps/buffgym/buffgym-set.js new file mode 100644 index 000000000..efb3c2582 --- /dev/null +++ b/apps/buffgym/buffgym-set.js @@ -0,0 +1,28 @@ +exports = class Set { + constructor(maxReps) { + this.completed = false; + this.minReps = 0; + this.reps = 0; + this.maxReps = maxReps; + } + + isCompleted() { + return !!this.completed; + } + + setCompleted() { + this.completed = true; + } + + incReps() { + if (this.completed) return; + if (this.reps >= this.maxReps) return; + this.reps++; + } + + decReps() { + if (this.completed) return; + if (this.reps <= this.minReps) return; + this.reps--; + } +}; \ No newline at end of file diff --git a/apps/buffgym/buffgym-workout-a.json b/apps/buffgym/buffgym-workout-a.json new file mode 100644 index 000000000..8eb8611d6 --- /dev/null +++ b/apps/buffgym/buffgym-workout-a.json @@ -0,0 +1,33 @@ +{ + "title": "Workout A", + "exercises": [ + { + "title": "Squats", + "weight": 40, + "unit": "Kg", + "sets": [5, 5, 5, 5, 5], + "restPeriod": 90 + }, + { + "title": "Overhead press", + "weight": 20, + "unit": "Kg", + "sets": [5, 5, 5, 5, 5], + "restPeriod": 90 + }, + { + "title": "Deadlift", + "weight": 20, + "unit": "Kg", + "sets": [5], + "restPeriod": 90 + }, + { + "title": "Pullups", + "weight": 0, + "unit": "Kg", + "sets": [10, 10, 10], + "restPeriod": 90 + } + ] +} \ No newline at end of file diff --git a/apps/buffgym/buffgym-workout-b.json b/apps/buffgym/buffgym-workout-b.json new file mode 100644 index 000000000..43845a98b --- /dev/null +++ b/apps/buffgym/buffgym-workout-b.json @@ -0,0 +1,33 @@ +{ + "title": "Workout B", + "exercises": [ + { + "title": "Squats", + "weight": 40, + "unit": "Kg", + "sets": [5, 5, 5, 5, 5], + "restPeriod": 90 + }, + { + "title": "Bench press", + "weight": 20, + "unit": "Kg", + "sets": [5, 5, 5, 5, 5], + "restPeriod": 90 + }, + { + "title": "Row", + "weight": 20, + "unit":"Kg", + "sets": [5, 5, 5, 5, 5], + "restPeriod": 90 + }, + { + "title": "Tricep extension", + "weight": 20, + "unit": "Kg", + "sets": [10, 10, 10], + "restPeriod": 90 + } + ] +} \ No newline at end of file diff --git a/apps/buffgym/buffgym-workout-index.json b/apps/buffgym/buffgym-workout-index.json new file mode 100644 index 000000000..af74d5e3b --- /dev/null +++ b/apps/buffgym/buffgym-workout-index.json @@ -0,0 +1,10 @@ +[ + { + "title": "Workout A", + "file": "buffgym-workout-a.json" + }, + { + "title": "Workout B", + "file": "buffgym-workout-b.json" + } +] \ No newline at end of file diff --git a/apps/buffgym/buffgym-workout.js b/apps/buffgym/buffgym-workout.js new file mode 100644 index 000000000..770ed5ffa --- /dev/null +++ b/apps/buffgym/buffgym-workout.js @@ -0,0 +1,84 @@ +exports = class Workout { + constructor(params) { + this.title = params.title; + this.exercises = []; + this.completed = false; + this.on("redraw", params.redraw.bind(null, this)); + } + + addExercises(exercises) { + exercises.forEach(exercise => this.exercises.push(exercise)); + } + + currentExercise() { + return this.exercises.filter(exercise => !exercise.isCompleted())[0]; + } + + canComplete() { + return this.exercises.filter(exercise => exercise.isCompleted()).length === this.exercises.length; + } + + setCompleted() { + if (!this.canComplete()) throw "All exercises must be completed"; + this.completed = true; + } + + isCompleted() { + return !!this.completed; + } + + static fromJSON(workoutJSON, redraw) { + const Set = require("buffgym-set.js"); + const Exercise = require("buffgym-exercise.js"); + const workout = new this({ + title: workoutJSON.title, + redraw: redraw, + }); + const exercises = workoutJSON.exercises.map(exerciseJSON => { + const exercise = new Exercise({ + title: exerciseJSON.title, + weight: exerciseJSON.weight, + weightIncrement: exerciseJSON.weightIncrement, + unit: exerciseJSON.unit, + restPeriod: exerciseJSON.restPeriod, + }); + exerciseJSON.sets.forEach(setJSON => { + exercise.addSet(new Set(setJSON)); + }); + + return exercise; + }); + + workout.addExercises(exercises); + + return workout; + } + + toJSON() { + return { + title: this.title, + exercises: this.exercises.map(exercise => { + return { + title: exercise.title, + weight: exercise.weight, + weightIncrement: exercise.weightIncrement, + unit: exercise.unit, + sets: exercise.sets.map(set => set.maxReps), + restPeriod: exercise.restPeriod, + }; + }), + }; + } + + // State machine + next() { + if (this.canComplete()) { + this.setCompleted(); + this.emit("redraw"); + return; + } + + // Call current exercise state machine + this.currentExercise().next(this); + } +}; \ No newline at end of file diff --git a/apps/buffgym/buffgym.app.js b/apps/buffgym/buffgym.app.js new file mode 100755 index 000000000..7ed7db1bd --- /dev/null +++ b/apps/buffgym/buffgym.app.js @@ -0,0 +1,261 @@ +/** + * BangleJS Stronglifts 5x5 training aid + * + * Original Author: Paul Cockrell https://github.com/paulcockrell + * Created: April 2020 + * + * Inspired by: + * - Stronglifts 5x5 training workout https://stronglifts.com/5x5/ + * - Stronglifts smart watch app + */ + +Bangle.setLCDMode("120x120"); + +const W = g.getWidth(); +const H = g.getHeight(); +const RED = "#d32e29"; +const PINK = "#f05a56"; +const WHITE = "#ffffff"; + +function drawMenu(params) { + const hs = require("heatshrink"); + const incImg = hs.decompress(atob("gsFwMAkM+oUA")); + const decImg = hs.decompress(atob("gsFwIEBnwCBA")); + const okImg = hs.decompress(atob("gsFwMAhGFo0A")); + const DEFAULT_PARAMS = { + showBTN1: false, + showBTN2: false, + showBTN3: false, + }; + const p = Object.assign({}, DEFAULT_PARAMS, params); + if (p.showBTN1) g.drawImage(incImg, W - 10, 10); + if (p.showBTN2) g.drawImage(okImg, W - 10, 60); + if (p.showBTN3) g.drawImage(decImg, W - 10, 110); +} + +function drawSet(exercise) { + const set = exercise.currentSet(); + if (set.isCompleted()) return; + + g.clear(); + + // Draw exercise title + g.setColor(PINK); + g.fillRect(15, 0, W - 15, 18); + g.setFontAlign(0, -1); + g.setFont("6x8", 1); + g.setColor(WHITE); + g.drawString(exercise.title, W / 2, 5); + g.setFont("6x8", 1); + g.drawString(exercise.weight + " " + exercise.unit, W / 2, 27); + // Draw completed reps counter + g.setFontAlign(0, 0); + g.setColor(PINK); + g.fillRect(15, 42, W - 15, 80); + g.setColor(WHITE); + g.setFont("6x8", 5); + g.drawString(set.reps, (W / 2) + 2, (H / 2) + 1); + g.setFont("6x8", 1); + const note = `Target reps: ${set.maxReps}`; + g.drawString(note, W / 2, H - 24); + // Draw sets monitor + g.drawString(exercise.subTitle, W / 2, H - 12); + + drawMenu({showBTN1: true, showBTN2: true, showBTN3: true}); + + g.flip(); +} + +function drawWorkoutDone() { + const title1 = "You did"; + const title2 = "GREAT!"; + const msg = "That's the workout\ncompleted. Now eat\nsome food and\nget plenty of rest."; + + clearWatch(); + setWatch(Bangle.showLauncher, BTN2, {repeat: false}); + drawMenu({showBTN2: true}); + + g.setFontAlign(0, -1); + g.setColor(WHITE); + g.setFont("6x8", 2); + g.drawString(title1, W / 2, 10); + g.drawString(title2, W / 2, 30); + g.setFont("6x8", 1); + g.drawString(msg, (W / 2) + 3, 70); + g.flip(); +} + +function drawSetComp(exercise) { + const title = "Good work"; + const msg1= "No need to rest\nmove straight on\nto the next\nexercise."; + const msg2 = exercise.canProgress()? + "Your\nweight has been\nincreased for\nnext time!": + "You'll\nsmash it next\ntime!"; + + g.clear(); + drawMenu({showBTN2: true}); + + g.setFontAlign(0, -1); + g.setColor(WHITE); + g.setFont("6x8", 2); + g.drawString(title, W / 2, 10); + g.setFont("6x8", 1); + g.drawString(msg1 + msg2, (W / 2) - 2, 45); + + g.flip(); +} + +function drawRestTimer(exercise) { + g.clear(); + drawMenu({showBTN2: true}); + g.setFontAlign(0, -1); + g.setColor(PINK); + g.fillRect(15, 42, W - 15, 80); + g.setColor(WHITE); + g.setFont("6x8", 1); + g.drawString("Have a short\nrest period.", W / 2, 10); + g.setFont("6x8", 5); + g.drawString(exercise.restPeriod, (W / 2) + 2, (H / 2) - 19); + g.flip(); +} + +function redraw(workout) { + const exercise = workout.currentExercise(); + g.clear(); + + if (workout.isCompleted()) { + saveWorkout(workout); + drawWorkoutDone(); + return; + } + + if (exercise.isRestTimerRunning()) { + if (exercise.isLastSet()) { + drawSetComp(exercise); + } else { + drawRestTimer(exercise); + } + + return; + } + + drawSet(exercise); +} + +function drawWorkoutMenu(workouts, selWorkoutIdx) { + g.clear(); + g.setFontAlign(0, -1); + g.setColor(WHITE); + g.setFont("6x8", 2); + g.drawString("BuffGym", W / 2, 10); + + g.setFont("6x8", 1); + g.setFontAlign(-1, -1); + let selectedWorkout = workouts[selWorkoutIdx].title; + let yPos = 50; + workouts.forEach(workout => { + g.setColor("#f05a56"); + g.fillRect(0, yPos, W, yPos + 11); + g.setColor("#ffffff"); + if (selectedWorkout === workout.title) { + g.drawRect(0, yPos, W - 1, yPos + 11); + } + g.drawString(workout.title, 10, yPos + 2); + yPos += 15; + }); + g.flip(); +} + +function setupMenu() { + clearWatch(); + const workouts = getWorkoutIndex(); + let selWorkoutIdx = 0; + drawWorkoutMenu(workouts, selWorkoutIdx); + + setWatch(()=>{ + selWorkoutIdx--; + if (selWorkoutIdx< 0) selWorkoutIdx = 0; + drawWorkoutMenu(workouts, selWorkoutIdx); + }, BTN1, {repeat: true}); + + setWatch(()=>{ + const workout = buildWorkout(workouts[selWorkoutIdx].file); + workout.next(); + }, BTN2, {repeat: false}); + + setWatch(()=>{ + selWorkoutIdx++; + if (selWorkoutIdx > workouts.length - 1) selWorkoutIdx = workouts.length - 1; + drawWorkoutMenu(workouts, selWorkoutIdx); + }, BTN3, {repeat: true}); +} + +function drawSplash() { + g.reset(); + g.setBgColor(RED); + g.clear(); + g.setColor(WHITE); + g.setFontAlign(0,-1); + g.setFont("6x8", 2); + g.drawString("BuffGym", W / 2, 10); + g.setFont("6x8", 1); + g.drawString("5x5", W / 2, 42); + g.drawString("training app", W / 2, 55); + g.drawRect(19, 38, 100, 99); + const img = require("heatshrink").decompress(atob("lkdxH+AB/I5ASQACwpB5vNFkwpBAIfNFdZZkFYwskFZAsiFZBZiVYawEFf6ETFUwsIFUYmB54ADAwIskFYoRKBoIroB4grV58kkgCDFRotWFZwqHFiwYMFZIsTC5wLDFjGlCoWlkgJDRQIABCRAsLCwodCFAIABCwIOCFQYABr4RCCQIrMC4gqEAAwpFFZosFC5ArHFQ4rFNYQrGEgosMBxIrFLQwrLAB4sFSw4rFFjYrQFi4rNbASeEFjIoJFQYsGMAgAPEQgAIGwosCRoorbA=")); + g.drawImage(img, 40, 70); + g.flip(); + + let flasher = false; + let bgCol, txtCol; + const i = setInterval(() => { + if (flasher) { + bgCol = WHITE; + txtCol = RED; + } else { + bgCol = RED; + txtCol = WHITE; + } + flasher = !flasher; + g.setColor(bgCol); + g.fillRect(0, 108, W, 120); + g.setColor(txtCol); + g.drawString("Press btn to begin", W / 2, 110); + g.flip(); + }, 250); + + setWatch(()=>{ + clearInterval(i); + setupMenu(); + }, BTN1, {repeat: false}); + + setWatch(()=>{ + clearInterval(i); + setupMenu(); + }, BTN2, {repeat: false}); + + setWatch(()=>{ + clearInterval(i); + setupMenu(); + }, BTN3, {repeat: false}); +} + +function getWorkoutIndex() { + const workoutIdx = require("Storage").readJSON("buffgym-workout-index.json"); + return workoutIdx; +} + +function buildWorkout(fName) { + const Workout = require("buffgym-workout.js"); + const workoutJSON = require("Storage").readJSON(fName); + const workout = Workout.fromJSON(workoutJSON, redraw); + + return workout; +} + +function saveWorkout(workout) { + const fName = getWorkoutIndex().find(w => w.title === workout.title).file; + require("Storage").writeJSON(fName, workout.toJSON()); +} + +drawSplash(); \ No newline at end of file diff --git a/apps/buffgym/buffgym.html b/apps/buffgym/buffgym.html new file mode 100644 index 000000000..26d3905ee --- /dev/null +++ b/apps/buffgym/buffgym.html @@ -0,0 +1,250 @@ + + + + + +

BuffGym

+

+ Enter in your weights for each exercise, start light and keep consistent with your training. The weight increment field is how much the app will increase your weights for an exercise if you successfully complete all the reps and sets for an exercise. Make sure its a value that matches the weights in your gym. +

+

+ For more information on how to train this program refer the Stronglifts website +

+
+

Workout A

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExerciseSets / RepsWeightWeight increment
+ Squats + + 5x5 + + + + +
+ Overhead press + + 5x5 + + + + +
+ Deadlift + + 1x5 + + + + +
+ Pullups + + 3x10 + + + + +
+

Workout B

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExerciseSets / RepsWeightWeight increment
+ Squats + + 5x5 + + + + +
+ Bench press + + 5x5 + + + + +
+ Row + + 5x5 + + + + +
+ Tricep extension + + 3x10 + + + + +
+
+

+ + + + + + + diff --git a/apps/buffgym/buffgym.png b/apps/buffgym/buffgym.png new file mode 100755 index 000000000..9bde64cc4 Binary files /dev/null and b/apps/buffgym/buffgym.png differ diff --git a/apps/calculator/ChangeLog b/apps/calculator/ChangeLog index 5560f00bc..3b9b23270 100644 --- a/apps/calculator/ChangeLog +++ b/apps/calculator/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: fix precision rounding issue + no reset when equals pressed diff --git a/apps/calculator/README.md b/apps/calculator/README.md new file mode 100644 index 000000000..b25d355bf --- /dev/null +++ b/apps/calculator/README.md @@ -0,0 +1,23 @@ +# Calculator + +Basic calculator reminiscent of MacOs's one. Handy for small calculus. + + + +## Features + +- add / substract / divide / multiply +- handles floats +- basic memory button + +## Controls + +- UP: BTN1 +- DOWN: BTN3 +- LEFT: BTN4 +- RIGHT: BTN5 +- SELECT: BTN2 + +## Creator + + diff --git a/apps/calculator/app.js b/apps/calculator/app.js index 91dd7c49d..a736b715d 100644 --- a/apps/calculator/app.js +++ b/apps/calculator/app.js @@ -144,19 +144,57 @@ function drawKey(name, k, selected) { g.drawString(k.val || name, k.xy[0] + RIGHT_MARGIN + rMargin, k.xy[1] + BOTTOM_MARGIN + bMargin); } +function getIntWithPrecision(x) { + var xStr = x.toString(); + var xRadix = xStr.indexOf('.'); + var xPrecision = xRadix === -1 ? 0 : xStr.length - xRadix - 1; + return { + num: Number(xStr.replace('.', '')), + p: xPrecision + }; +} + +function multiply(x, y) { + var xNum = getIntWithPrecision(x); + var yNum = getIntWithPrecision(y); + return xNum.num * yNum.num / Math.pow(10, xNum.p + yNum.p); +} + +function divide(x, y) { + var xNum = getIntWithPrecision(x); + var yNum = getIntWithPrecision(y); + return xNum.num / yNum.num / Math.pow(10, xNum.p - yNum.p); +} + +function sum(x, y) { + let xNum = getIntWithPrecision(x); + let yNum = getIntWithPrecision(y); + + let diffPrecision = Math.abs(xNum.p - yNum.p); + if (diffPrecision > 0) { + if (xNum.p > yNum.p) { + yNum.num = yNum.num * Math.pow(10, diffPrecision); + } else { + xNum.num = xNum.num * Math.pow(10, diffPrecision); + } + } + return (xNum.num + yNum.num) / Math.pow(10, Math.max(xNum.p, yNum.p)); +} + +function subtract(x, y) { + return sum(x, -y); +} + function doMath(x, y, operator) { - // might not be a number due to display of dot "." algo - x = Number(x); - y = Number(y); switch (operator) { case '/': - return x / y; + return divide(x, y); case '*': - return x * y; + return multiply(x, y); case '+': - return x + y; + return sum(x, y); case '-': - return x - y; + return subtract(x, y); } } @@ -204,7 +242,7 @@ function displayOutput(num) { } len = (num + '').length; - if (numNumeric < 0) { + if (numNumeric < 0 || (numNumeric === 0 && 1/numNumeric === -Infinity)) { // minus is not available in font 7x11Numeric7Seg, we use Vector g.setFont('Vector', 20); g.drawString('-', 220 - (len * 15), 10); @@ -214,18 +252,33 @@ function displayOutput(num) { } g.drawString(num, 220 - (len * 15) + minusMarge, 10); } - +var wasPressedEquals = false; +var hasPressedNumber = false; function calculatorLogic(x) { - if (hasPressedEquals) { - currNumber = results; + if (wasPressedEquals && hasPressedNumber !== false) { prevNumber = null; - operator = null; - results = null; - isDecimal = null; - displayOutput(currNumber); - hasPressedEquals = false; + currNumber = hasPressedNumber; + wasPressedEquals = false; + hasPressedNumber = false; + return; } - if (prevNumber != null && currNumber != null && operator != null) { + if (hasPressedEquals) { + if (hasPressedNumber) { + prevNumber = null; + hasPressedNumber = false; + operator = null; + } else { + currNumber = null; + prevNumber = results; + } + hasPressedEquals = false; + wasPressedEquals = true; + } + + if (currNumber == null && operator != null && '/*-+'.indexOf(x) !== -1) { + operator = x; + displayOutput(prevNumber); + } else if (prevNumber != null && currNumber != null && operator != null) { // we execute the calculus only when there was a previous number entered before and an operator results = doMath(prevNumber, currNumber, operator); operator = x; @@ -255,8 +308,10 @@ function buttonPress(val) { operator = null; } else { keys.R.val = 'AC'; - drawKey('R', keys.R); + drawKey('R', keys.R, true); } + wasPressedEquals = false; + hasPressedNumber = false; displayOutput(0); break; case '%': @@ -265,11 +320,12 @@ function buttonPress(val) { } else if (currNumber != null) { displayOutput(currNumber /= 100); } + hasPressedNumber = false; break; case 'N': if (results != null) { displayOutput(results *= -1); - } else if (currNumber != null) { + } else { displayOutput(currNumber *= -1); } break; @@ -278,6 +334,7 @@ function buttonPress(val) { case '-': case '+': calculatorLogic(val); + hasPressedNumber = false; break; case '.': keys.R.val = 'C'; @@ -290,18 +347,24 @@ function buttonPress(val) { results = doMath(prevNumber, currNumber, operator); prevNumber = results; displayOutput(results); - hasPressedEquals = true; + hasPressedEquals = 1; } + hasPressedNumber = false; break; default: keys.R.val = 'C'; drawKey('R', keys.R); + const is0Negative = (currNumber === 0 && 1/currNumber === -Infinity); if (isDecimal) { - currNumber = currNumber == null ? 0 + '.' + val : currNumber + '.' + val; + currNumber = currNumber == null || hasPressedEquals === 1 ? 0 + '.' + val : currNumber + '.' + val; isDecimal = false; } else { - currNumber = currNumber == null ? val : currNumber + val; + currNumber = currNumber == null || hasPressedEquals === 1 ? val : (is0Negative ? '-' + val : currNumber + val); } + if (hasPressedEquals === 1) { + hasPressedEquals = 2; + } + hasPressedNumber = currNumber; displayOutput(currNumber); break; } @@ -309,44 +372,21 @@ function buttonPress(val) { for (var k in keys) { if (keys.hasOwnProperty(k)) { - drawKey(k, keys[k], k == '5'); + drawKey(k, keys[k], k == '5'); } } g.setFont('7x11Numeric7Seg', 2.8); g.drawString('0', 205, 10); - -setWatch(function() { - drawKey(selected, keys[selected]); - // key 0 is 2 keys wide, go up to 1 if it was previously selected - if (selected == '0' && prevSelected === '1') { - prevSelected = selected; - selected = '1'; - } else { - prevSelected = selected; - selected = keys[selected].trbl[0]; - } - drawKey(selected, keys[selected], true); -}, BTN1, {repeat: true, debounce: 100}); - -setWatch(function() { +function moveDirection(d) { drawKey(selected, keys[selected]); prevSelected = selected; - selected = keys[selected].trbl[2]; + selected = (d === 0 && selected == '0' && prevSelected === '1') ? '1' : keys[selected].trbl[d]; drawKey(selected, keys[selected], true); -}, BTN3, {repeat: true, debounce: 100}); +} -Bangle.on('touch', function(direction) { - drawKey(selected, keys[selected]); - prevSelected = selected; - if (direction == 1) { - selected = keys[selected].trbl[3]; - } else if (direction == 2) { - selected = keys[selected].trbl[1]; - } - drawKey(selected, keys[selected], true); -}); - -setWatch(function() { - buttonPress(selected); -}, BTN2, {repeat: true, debounce: 100}); +setWatch(_ => moveDirection(0), BTN1, {repeat: true, debounce: 100}); +setWatch(_ => moveDirection(2), BTN3, {repeat: true, debounce: 100}); +setWatch(_ => moveDirection(3), BTN4, {repeat: true, debounce: 100}); +setWatch(_ => moveDirection(1), BTN5, {repeat: true, debounce: 100}); +setWatch(_ => buttonPress(selected), BTN2, {repeat: true, debounce: 100}); diff --git a/apps/calculator/tests.html b/apps/calculator/tests.html new file mode 100644 index 000000000..1cbfdf617 --- /dev/null +++ b/apps/calculator/tests.html @@ -0,0 +1,273 @@ + + + + + + Calculator tests + + + + + + +
+ + + + + + + diff --git a/apps/calendar/ChangeLog b/apps/calendar/ChangeLog new file mode 100644 index 000000000..3cf79ffe8 --- /dev/null +++ b/apps/calendar/ChangeLog @@ -0,0 +1 @@ +0.01: Basic calendar diff --git a/apps/calendar/README.md b/apps/calendar/README.md new file mode 100644 index 000000000..19a60afc0 --- /dev/null +++ b/apps/calendar/README.md @@ -0,0 +1,8 @@ +# Calendar + +Basic calendar + +## Usage + +- Use `BTN4` (left screen tap) to go to the previous month +- Use `BTN5` (right screen tap) to go to the next month diff --git a/apps/calendar/calendar-icon.js b/apps/calendar/calendar-icon.js new file mode 100644 index 000000000..ed1bf3667 --- /dev/null +++ b/apps/calendar/calendar-icon.js @@ -0,0 +1,5 @@ +require("heatshrink").decompress( + atob( + "mEwxH+AH4A/ADuIUCARRDhgePCKIv13YAEDoYJFAA4RJFyQvcGBYRGy4dDy4uLCJgv/DoOBDgOBF5oRLF6IeBDgIvNCJYvQDwQuNCJovRADov/F9OsAEgv/F/4vhwIACAqYv/F/4vnd94vvX/4v/F/7vvF96//F/4v/d94v/F/4wsFxQwjFxgA/AH4A/AH4AZA==" + ) +) diff --git a/apps/calendar/calendar.js b/apps/calendar/calendar.js new file mode 100644 index 000000000..720986162 --- /dev/null +++ b/apps/calendar/calendar.js @@ -0,0 +1,160 @@ +const maxX = 240; +const maxY = 240; +const rowN = 7; +const colN = 7; +const headerH = maxY / 7; +const rowH = (maxY - headerH) / rowN; +const colW = maxX / colN; +const color1 = "#035AA6"; +const color2 = "#4192D9"; +const color3 = "#026873"; +const color4 = "#038C8C"; +const color5 = "#03A696"; +const black = "#000000"; +const white = "#ffffff"; +const gray1 = "#444444"; +const gray2 = "#888888"; +const gray3 = "#bbbbbb"; +const red = "#d41706"; + +function drawCalendar(date) { + g.setBgColor(color4); + g.clearRect(0, 0, maxX, maxY); + g.setBgColor(color1); + g.clearRect(0, 0, maxX, headerH); + g.setBgColor(color2); + g.clearRect(0, headerH, maxX, headerH + rowH); + g.setBgColor(color3); + g.clearRect(colW * 5, headerH + rowH, maxX, maxY); + for (let y = headerH; y < maxY; y += rowH) { + g.drawLine(0, y, maxX, y); + } + for (let x = 0; x < maxX; x += colW) { + g.drawLine(x, headerH, x, maxY); + } + + const month = date.getMonth(); + const year = date.getFullYear(); + const monthMap = { + 0: "January", + 1: "February", + 2: "March", + 3: "April", + 4: "May", + 5: "June", + 6: "July", + 7: "August", + 8: "September", + 9: "October", + 10: "November", + 11: "December" + }; + g.setFontAlign(0, 0); + g.setFont("6x8", 2); + g.setColor(white); + g.drawString(`${monthMap[month]} ${year}`, maxX / 2, headerH / 2); + g.drawPoly([10, headerH / 2, 20, 10, 20, headerH - 10], true); + g.drawPoly( + [maxX - 10, headerH / 2, maxX - 20, 10, maxX - 20, headerH - 10], + true + ); + + g.setFont("6x8", 2); + const dowLbls = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"]; + dowLbls.forEach((lbl, i) => { + g.drawString(lbl, i * colW + colW / 2, headerH + rowH / 2); + }); + + date.setDate(1); + const dow = date.getDay(); + const dowNorm = dow === 0 ? 7 : dow; + + const monthMaxDayMap = { + 0: 31, + 1: (2020 - year) % 4 === 0 ? 29 : 28, + 2: 31, + 3: 30, + 4: 31, + 5: 30, + 6: 31, + 7: 31, + 8: 30, + 9: 31, + 10: 30, + 11: 31 + }; + + let days = []; + let nextMonthDay = 1; + let thisMonthDay = 51; + let prevMonthDay = monthMaxDayMap[month > 0 ? month - 1 : 11] - dowNorm; + for (let i = 0; i < colN * (rowN - 1) + 1; i++) { + if (i < dowNorm) { + days.push(prevMonthDay); + prevMonthDay++; + } else if (thisMonthDay <= monthMaxDayMap[month] + 50) { + days.push(thisMonthDay); + thisMonthDay++; + } else { + days.push(nextMonthDay); + nextMonthDay++; + } + } + + let i = 0; + for (y = 0; y < rowN - 1; y++) { + for (x = 0; x < colN; x++) { + i++; + const day = days[i]; + const isToday = + today.year === year && today.month === month && today.day === day - 50; + if (isToday) { + g.setColor(red); + g.drawRect( + x * colW, + y * rowH + headerH + rowH, + x * colW + colW - 1, + y * rowH + headerH + rowH + rowH + ); + } + g.setColor(day < 50 ? gray3 : white); + g.drawString( + (day > 50 ? day - 50 : day).toString(), + x * colW + colW / 2, + headerH + rowH + y * rowH + rowH / 2 + ); + } + } +} + +const date = new Date(); +const today = { + day: date.getDate(), + month: date.getMonth(), + year: date.getFullYear() +}; +drawCalendar(date); +clearWatch(); +setWatch( + () => { + const month = date.getMonth(); + const prevMonth = month > 0 ? month - 1 : 11; + if (prevMonth === 11) date.setFullYear(date.getFullYear() - 1); + date.setMonth(prevMonth); + drawCalendar(date); + }, + BTN4, + { repeat: true } +); +setWatch( + () => { + const month = date.getMonth(); + const prevMonth = month < 11 ? month + 1 : 0; + if (prevMonth === 0) date.setFullYear(date.getFullYear() + 1); + date.setMonth(month + 1); + drawCalendar(date); + }, + BTN5, + { repeat: true } +); +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); diff --git a/apps/calendar/calendar.png b/apps/calendar/calendar.png new file mode 100644 index 000000000..056cab3b7 Binary files /dev/null and b/apps/calendar/calendar.png differ diff --git a/apps/chrono/ChangeLog b/apps/chrono/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/chrono/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/chronowid/ChangeLog b/apps/chronowid/ChangeLog index a6f342f01..e173467a1 100644 --- a/apps/chronowid/ChangeLog +++ b/apps/chronowid/ChangeLog @@ -1 +1,3 @@ 0.01: New widget and app! +0.02: Setting to reset values, timer buzzes at 00:00 and not later (see readme) +0.03: Display only minutes:seconds when less than 1 hour left \ No newline at end of file diff --git a/apps/chronowid/README.md b/apps/chronowid/README.md index f31c24c7b..f422dd956 100644 --- a/apps/chronowid/README.md +++ b/apps/chronowid/README.md @@ -5,6 +5,8 @@ The advantage is, that you can still see your normal watchface and other widgets The widget is always active, but only shown when the timer is on. Hours, minutes, seconds and timer status can be set with an app. +Depending on when you start the timer, it may alert up to 0,999 seconds early. This is because it checks only for full seconds. When there is less than one seconds left, it buzzes. This cannot be avoided without checking more than every second, which I would like to avoid. + ## Screenshots TBD @@ -18,18 +20,19 @@ TBD There are no settings section in the settings app, timer can be set using an app. +* Reset values: Reset hours, minutes, seconds to 0; set timer on to false; write to settings file * Hours: Set the hours for the timer * Minutes: Set the minutes for the timer * Seconds: Set the seconds for the timer -* Timer on: Starts the timer and displays the widget when set to 'On'. You have to leave the app. The widget is always there, but only visible when timer is on. +* Timer on: Starts the timer and displays the widget when set to 'On'. You have to leave the app to load the widget which starts the timer. The widget is always there, but only visible when timer is on. ## Releases -* Offifical app loader: Not yet published. +* Offifical app loader: https://github.com/espruino/BangleApps/tree/master/apps/chronowid (https://banglejs.com/apps/) * Forked app loader: https://github.com/Purple-Tentacle/BangleApps/tree/master/apps/chronowid (https://purple-tentacle.github.io/BangleApps/index.html#) * Development: https://github.com/Purple-Tentacle/BangleAppsDev/tree/master/apps/chronowid ## Requests -If you have any feature requests, please contact me on the Espruino forum: http://forum.espruino.com/profiles/155005/ \ No newline at end of file +If you have any feature requests, please write here: http://forum.espruino.com/conversations/345972/ \ No newline at end of file diff --git a/apps/chronowid/app.js b/apps/chronowid/app.js index 48401a7bb..0cacdee23 100644 --- a/apps/chronowid/app.js +++ b/apps/chronowid/app.js @@ -30,7 +30,6 @@ settingsChronowid = storage.readJSON('chronowid.json',1); if (!settingsChronowid) resetSettings(); E.on('kill', () => { - print("-KILL-"); updateSettings(); }); @@ -45,6 +44,14 @@ function showMenu() { timerMenu.started.value = settingsChronowid.started; } }, + 'Reset values': function() { + settingsChronowid.hours = 0; + settingsChronowid.minutes = 0; + settingsChronowid.seconds = 0; + settingsChronowid.started = false; + updateSettings(); + showMenu(); + }, 'Hours': { value: settingsChronowid.hours, min: 0, @@ -82,10 +89,10 @@ function showMenu() { settingsChronowid.started = v; updateSettings(); } - }, - }; + }, + }; timerMenu['-Exit-'] = ()=>{load();}; return E.showMenu(timerMenu); } -showMenu(); +showMenu(); \ No newline at end of file diff --git a/apps/chronowid/widget.js b/apps/chronowid/widget.js index 708bc6345..f0e785efd 100644 --- a/apps/chronowid/widget.js +++ b/apps/chronowid/widget.js @@ -1,93 +1,93 @@ -(() => { - const storage = require('Storage'); - settingsChronowid = storage.readJSON("chronowid.json",1)||{}; //read settingsChronowid from file - var height = 23; - var width = 58; - var interval = 0; //used for the 1 second interval timer - var now = new Date(); - - var time = 0; - var diff = settingsChronowid.goal - now; - - //Convert ms to time - function getTime(t) { - var milliseconds = parseInt((t % 1000) / 100), - seconds = Math.floor((t / 1000) % 60), - minutes = Math.floor((t / (1000 * 60)) % 60), - hours = Math.floor((t / (1000 * 60 * 60)) % 24); - - hours = (hours < 10) ? "0" + hours : hours; - minutes = (minutes < 10) ? "0" + minutes : minutes; - seconds = (seconds < 10) ? "0" + seconds : seconds; - - return hours + ":" + minutes + ":" + seconds; - } - - function printDebug() { - print ("Nowtime: " + getTime(now)); - print ("Now: " + now); - print ("Goaltime: " + getTime(settingsChronowid.goal)); - print ("Goal: " + settingsChronowid.goal); - print("Difftime: " + getTime(diff)); - print("Diff: " + diff); - print ("Started: " + settingsChronowid.started); - print ("----"); - } - - //counts down, calculates and displays - function countDown() { - //printDebug(); - now = new Date(); - diff = settingsChronowid.goal - now; //calculate difference - WIDGETS["chronowid"].draw(); - //time is up - if (settingsChronowid.started && diff <= 0) { - Bangle.buzz(1500); - //write timer off to file - settingsChronowid.started = false; - storage.writeJSON('chronowid.json', settingsChronowid); - clearInterval(interval); //stop interval - //printDebug(); - } - } - - // draw your widget - function draw() { - if (!settingsChronowid.started) { - width = 0; - return; //do not draw anything if timer is not started - } - g.reset(); - if (diff >= 0) { - if (diff < 600000) { //less than 1 hour left - width = 58; - g.clearRect(this.x,this.y,this.x+width,this.y+height); - g.setFont("6x8", 2); - g.drawString(getTime(diff).substring(3), this.x+1, this.y+5); //remove hour part 00:00:00 -> 00:00 - } - if (diff >= 600000) { //one hour or more left - width = 48; - g.clearRect(this.x,this.y,this.x+width,this.y+height); - g.setFont("6x8", 1); - g.drawString(getTime(diff), this.x+1, this.y+((height/2)-4)); //display hour 00:00:00 - } - } - else { - width = 58; - g.clearRect(this.x,this.y,this.x+width,this.y+height); - g.setFont("6x8", 2); - g.drawString("END", this.x+15, this.y+5); - } - } - - if (settingsChronowid.started) interval = setInterval(countDown, 1000); //start countdown each second - - // add the widget - WIDGETS["chronowid"]={area:"bl",width:width,draw:draw,reload:function() { - reload(); - Bangle.drawWidgets(); // relayout all widgets - }}; - - //printDebug(); - countDown(); +(() => { + const storage = require('Storage'); + settingsChronowid = storage.readJSON("chronowid.json",1)||{}; //read settingsChronowid from file + var height = 23; + var width = 58; + var interval = 0; //used for the 1 second interval timer + var now = new Date(); + + var time = 0; + var diff = settingsChronowid.goal - now; + + //Convert ms to time + function getTime(t) { + var milliseconds = parseInt((t % 1000) / 100), + seconds = Math.floor((t / 1000) % 60), + minutes = Math.floor((t / (1000 * 60)) % 60), + hours = Math.floor((t / (1000 * 60 * 60)) % 24); + + hours = (hours < 10) ? "0" + hours : hours; + minutes = (minutes < 10) ? "0" + minutes : minutes; + seconds = (seconds < 10) ? "0" + seconds : seconds; + + return hours + ":" + minutes + ":" + seconds; + } + + function printDebug() { + print ("Nowtime: " + getTime(now)); + print ("Now: " + now); + print ("Goaltime: " + getTime(settingsChronowid.goal)); + print ("Goal: " + settingsChronowid.goal); + print("Difftime: " + getTime(diff)); + print("Diff: " + diff); + print ("Started: " + settingsChronowid.started); + print ("----"); + } + + //counts down, calculates and displays + function countDown() { + now = new Date(); + diff = settingsChronowid.goal - now; //calculate difference + WIDGETS["chronowid"].draw(); + //time is up + if (settingsChronowid.started && diff < 1000) { + Bangle.buzz(1500); + //write timer off to file + settingsChronowid.started = false; + storage.writeJSON('chronowid.json', settingsChronowid); + clearInterval(interval); //stop interval + } + //printDebug(); + } + + // draw your widget + function draw() { + if (!settingsChronowid.started) { + width = 0; + return; //do not draw anything if timer is not started + } + g.reset(); + if (diff >= 0) { + if (diff < 3600000) { //less than 1 hour left + width = 58; + g.clearRect(this.x,this.y,this.x+width,this.y+height); + g.setFont("6x8", 2); + g.drawString(getTime(diff).substring(3), this.x+1, this.y+5); //remove hour part 00:00:00 -> 00:00 + } + if (diff >= 3600000) { //one hour or more left + width = 48; + g.clearRect(this.x,this.y,this.x+width,this.y+height); + g.setFont("6x8", 1); + g.drawString(getTime(diff), this.x+1, this.y+((height/2)-4)); //display hour 00:00:00 + } + } + // not needed anymoe, because we check if diff < 1000 now, so 00:00 is displayed. + // else { + // width = 58; + // g.clearRect(this.x,this.y,this.x+width,this.y+height); + // g.setFont("6x8", 2); + // g.drawString("END", this.x+15, this.y+5); + // } + } + + if (settingsChronowid.started) interval = setInterval(countDown, 1000); //start countdown each second + + // add the widget + WIDGETS["chronowid"]={area:"bl",width:width,draw:draw,reload:function() { + reload(); + Bangle.drawWidgets(); // relayout all widgets + }}; + + //printDebug(); + countDown(); })(); \ No newline at end of file diff --git a/apps/clickms/ChangeLog b/apps/clickms/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/clickms/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/clickms/click-master.js b/apps/clickms/click-master.js index b9f76364b..55027e733 100644 --- a/apps/clickms/click-master.js +++ b/apps/clickms/click-master.js @@ -7,12 +7,12 @@ setWatch(x=>{ },BTN1,{repeat:true}); function updateAdvertising() { -try { - NRF.setAdvertising({},{ - manufacturer: 0x0590, - manufacturerData: new Uint8Array([mycounter>>8,mycounter&255]) - }); -} catch(e){} + try { + NRF.setAdvertising({},{ + manufacturer: 0x0590, + manufacturerData: new Uint8Array([mycounter>>8,mycounter&255]) + }); + } catch(e){} } function drawPlayers() { diff --git a/apps/cliock/ChangeLog b/apps/cliock/ChangeLog index 081a638f6..59f07c400 100644 --- a/apps/cliock/ChangeLog +++ b/apps/cliock/ChangeLog @@ -1 +1,2 @@ 0.07: Submitted to App Loader +0.08: Fixes issue where face would redraw on wake leading to all memory being used and watch crashing. diff --git a/apps/cliock/app.js b/apps/cliock/app.js index 20086464e..a94b7264d 100644 --- a/apps/cliock/app.js +++ b/apps/cliock/app.js @@ -5,9 +5,6 @@ var flag = false; var WeekDays = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]; function drawAll(){ - g.clear(); - Bangle.loadWidgets(); - Bangle.drawWidgets(); updateTime(); updateRest(new Date()); } @@ -42,6 +39,9 @@ function writeLine(str,line){ g.drawString(str,25,marginTop+line*30); } +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); drawAll(); Bangle.on('lcdPower',function(on) { if (on) diff --git a/apps/clock2x3/clock2x3-app.js b/apps/clock2x3/clock2x3-app.js index 511a7662b..4caec28cb 100644 --- a/apps/clock2x3/clock2x3-app.js +++ b/apps/clock2x3/clock2x3-app.js @@ -14,9 +14,9 @@ const x21=x20+pw+ps; const x30=x21+pw+ds; const x31=x30+pw+ps; const xSpace=[[x00,x01], // all pixel x spacing - [x10,x11], - [x20,x21], - [x30,x31]]; + [x10,x11], + [x20,x21], + [x30,x31]]; const y0=oy; // y spacing const y1=y0+pw+ps; @@ -24,35 +24,35 @@ const y2=y1+pw+ps; const ySpace=[y0, y1, y2]; const pixels = [[[0,0], // digit on/off pixels - [1,1], - [1,1]], - [[0,1], // digit 1 - [0,1], - [0,1]], - [[0,1], - [1,0], - [1,1]], - [[1,1], - [0,1], - [1,1]], - [[1,0], - [1,1], - [0,1]], - [[1,1], - [1,0], - [0,1]], - [[1,0], - [1,1], - [1,1]], - [[1,1], - [0,1], - [0,1]], - [[1,1], - [1,1], - [1,1]], - [[1,1], - [1,1], - [0,1]]]; + [1,1], + [1,1]], +[[0,1], // digit 1 + [0,1], + [0,1]], +[[0,1], + [1,0], + [1,1]], +[[1,1], + [0,1], + [1,1]], +[[1,0], + [1,1], + [0,1]], +[[1,1], + [1,0], + [0,1]], +[[1,0], + [1,1], + [1,1]], +[[1,1], + [0,1], + [0,1]], +[[1,1], + [1,1], + [1,1]], +[[1,1], + [1,1], + [0,1]]]; let idTimeout = null; diff --git a/apps/clotris/ChangeLog b/apps/clotris/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/clotris/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/compass/ChangeLog b/apps/compass/ChangeLog new file mode 100644 index 000000000..e70a5688b --- /dev/null +++ b/apps/compass/ChangeLog @@ -0,0 +1,3 @@ +0.01: New App! +0.02: Show text if uncalibrated +0.03: Eliminate flickering \ No newline at end of file diff --git a/apps/compass/compass.js b/apps/compass/compass.js index 10895e3cd..9b7ed56b7 100644 --- a/apps/compass/compass.js +++ b/apps/compass/compass.js @@ -1,34 +1,60 @@ -g.clear(); -g.setColor(0,0.5,1); -g.fillCircle(120,130,80,80); -g.setColor(0,0,0); -g.fillCircle(120,130,70,70); - -function arrow(r,c) { - r=r*Math.PI/180; - var p = Math.PI/2; - g.setColor(c); - g.fillPoly([ - 120+60*Math.sin(r), 130-60*Math.cos(r), - 120+10*Math.sin(r+p), 130-10*Math.cos(r+p), - 120+10*Math.sin(r+-p), 130-10*Math.cos(r-p), - ]); -} - -var oldHeading = 0; -Bangle.on('mag', function(m) { - if (!Bangle.isLCDOn()) return; - g.setFont("6x8",3); - g.setColor(0); - g.fillRect(70,0,170,24); - g.setColor(0xffff); - g.setFontAlign(0,0); - g.drawString(isNaN(m.heading)?"---":Math.round(m.heading),120,12); - g.setColor(0,0,0); - arrow(oldHeading,0); - arrow(oldHeading+180,0); - arrow(m.heading,0xF800); - arrow(m.heading+180,0x001F); - oldHeading = m.heading; -}); -Bangle.setCompassPower(1); +var tg = Graphics.createArrayBuffer(120,20,1,{msb:true}); +var timg = { + width:tg.getWidth(), + height:tg.getHeight(), + bpp:1, + buffer:tg.buffer +}; + +var ag = Graphics.createArrayBuffer(160,160,2,{msb:true}); +var aimg = { + width:ag.getWidth(), + height:ag.getHeight(), + bpp:2, + buffer:ag.buffer, + palette:new Uint16Array([0,0x03FF,0xF800,0x001F]) +}; +ag.setColor(1); +ag.fillCircle(80,80,79,79); +ag.setColor(0); +ag.fillCircle(80,80,69,69); + +function arrow(r,c) { + r=r*Math.PI/180; + var p = Math.PI/2; + ag.setColor(c); + ag.fillPoly([ + 80+60*Math.sin(r), 80-60*Math.cos(r), + 80+10*Math.sin(r+p), 80-10*Math.cos(r+p), + 80+10*Math.sin(r-p), 80-10*Math.cos(r-p), + ]); +} + +var oldHeading = 0; +Bangle.on('mag', function(m) { + if (!Bangle.isLCDOn()) return; + tg.clear(); + tg.setFont("6x8",1); + tg.setColor(1); + if (isNaN(m.heading)) { + tg.setFontAlign(0,-1); + tg.setFont("6x8",1); + tg.drawString("Uncalibrated",60,4); + tg.drawString("turn 360° around",60,12); + } + else { + tg.setFontAlign(0,0); + tg.setFont("6x8",2); + tg.drawString(Math.round(m.heading),60,12); + } + g.drawImage(timg,0,0,{scale:2}); + + ag.setColor(0); + arrow(oldHeading,0); + arrow(oldHeading+180,0); + arrow(m.heading,2); + arrow(m.heading+180,3); + g.drawImage(aimg,40,50); + oldHeading = m.heading; +}); +Bangle.setCompassPower(1); diff --git a/apps/counter/ChangeLog b/apps/counter/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/counter/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/counter/counter-icon.js b/apps/counter/counter-icon.js new file mode 100644 index 000000000..e894b2622 --- /dev/null +++ b/apps/counter/counter-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/ACcRiAWViURCycBj//+IwTgMv//yC63zC5sBiIAEI4QIFDo8SmYADmURmcRkYJEkIuGBooOBSAIIFmYwFgINGABIwFEo4XqmUiABJtCC46KBABYYBC48xF5gPBC48ikIPCiQDCkIIBAwMhC5ESdQIABkYDCmXx/8v+MxC7URbQQXEmYXCAYIXHgJ9BC4vxkUvkfyAYMy+X/BQIXCkMjmIXGB4MjAYUy+cRF4kxl4XOMYQXESgIXl+cSI4oMBO50/O4siL4ynH+cjU5rXHC4zXJC4y/BC4oADC4J9BkQABiQDCLAQGBkIXIkMyCYQAHkYPCC40yMwIAKkYXIDAIvLBwIXIABwXdgIJCIhEyC5RRBmJzHiUhicTC4LUCJCYuFGASmMAAIuGAH4A/AHo")) \ No newline at end of file diff --git a/apps/counter/counter.js b/apps/counter/counter.js new file mode 100644 index 000000000..9f77e34d8 --- /dev/null +++ b/apps/counter/counter.js @@ -0,0 +1,31 @@ +var counter = 0; + +g.setColor(0xFFFF); + +function updateScreen() { + g.clearRect(0, 50, 250, 150); + g.setFont("Vector",40).setFontAlign(0,0); + g.drawString(Math.floor(counter), g.getWidth()/2, 100); +} + + +// add a count by using BTN1 +setWatch(() => { + counter += 1; + updateScreen(); +}, BTN1, {repeat:true}); + +setWatch(() => { + counter = 0; + updateScreen(); +}, BTN3, {repeat:true}); + +g.clear(1).setFont("6x8"); +g.drawString('Use BTN1 to increase\nthe counter by one.\nUse BTN3 to reset counter.', 25, 200); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +// TODO: Enable saving counts to file +// Does not work if widgets are not visible +// Add small watch diff --git a/apps/counter/counter_icon.png b/apps/counter/counter_icon.png new file mode 100644 index 000000000..e5e4009bf Binary files /dev/null and b/apps/counter/counter_icon.png differ diff --git a/apps/cprassist/ChangeLog b/apps/cprassist/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/cprassist/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/cprassist/README.md b/apps/cprassist/README.md new file mode 100644 index 000000000..569f61149 --- /dev/null +++ b/apps/cprassist/README.md @@ -0,0 +1,24 @@ +# CPR Assist + +Provides assistance while performing a CPR + +## Usage + +The app alternates between the phases for +chest compression and rescue breaths in an in an endless loop. +In the chest compression phase the the watch will provide a +buzz at a rate of 100 rpm for 30 repetitions. +A longer buzz introduces an interval of 4 seconds to perform +2 rescue breaths. +A ratio of chest compressions to rescue breaths is also +displayed in the bottom of the screen. + +The number of repetitions for chest compression and +rescue breaths, the rpm rate and the duration of the +rescue breath phase can be adjusted in the settings. +See e.g. [CPR on Wikipedia](https://en.wikipedia.org/wiki/Cardiopulmonary_resuscitation) +for futher information and updates on the recommendations. + +## Attributions + +Icon source: https://commons.wikimedia.org/wiki/File:ISO_7010_E003_-_First_aid_sign.svg diff --git a/apps/cprassist/cprassist-icon.js b/apps/cprassist/cprassist-icon.js new file mode 100644 index 000000000..ec4667a8c --- /dev/null +++ b/apps/cprassist/cprassist-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AH4Arg93AB1wC/dxkQACi4XRuf/AAU3C/4X/C+sTmYABn4XD+YICmIXJl4TDAA/yC/4X/C+LXXAAdzC4c3BQgX/C/4X0uMiAAUXC6IAKC+wA/AH4AkA==")) diff --git a/apps/cprassist/cprassist-icon.png b/apps/cprassist/cprassist-icon.png new file mode 100644 index 000000000..c39962aaa Binary files /dev/null and b/apps/cprassist/cprassist-icon.png differ diff --git a/apps/cprassist/cprassist.js b/apps/cprassist/cprassist.js new file mode 100644 index 000000000..862ae54d6 --- /dev/null +++ b/apps/cprassist/cprassist.js @@ -0,0 +1,79 @@ +const SETTINGS_FILE = 'cprassist.settings.json'; +const SHORT_BUZZ_PERIOD = 80; +const LONG_BUZZ_PERIOD = 800; + +Bangle.setLCDTimeout(undefined); // do not deaktivate display while running this app + +let settings; + +function setting(key) { + const DEFAULTS = { + 'compression_count': 30, + 'breath_count': 2, + 'compression_rpm': 100, + 'breath_period_sec': 4 + }; + if (!settings) { + const storage = require("Storage"); + settings = storage.readJSON(SETTINGS_FILE, 1) || {}; + } + return (key in settings) + ? settings[key] + : DEFAULTS[key]; +} + +let counter = setting('compression_count'); + +function provideFeedback() { + let period = counter > 0 + ? SHORT_BUZZ_PERIOD + : LONG_BUZZ_PERIOD; + try { + Bangle.buzz(period, 1.0); + } catch(err) { + } +} + +function drawHeart() { + g.fillCircle(40, 92, 12); + g.fillCircle(60, 92, 12); + g.fillPoly([29, 98, 50, 120, 71, 98]); +} + +function updateScreen() { + const colors = [0xFFFF, 0x9492]; + g.reset().clearRect(0, 50, 250, 150); + if (counter > 0) { + g.setFont("Vector", 40).setFontAlign(0, 0); + g.setColor(colors[counter%2]); + drawHeart(); + g.drawString(counter + "", g.getWidth()/2, 100); + } else { + g.setFont("Vector", 20).setFontAlign(0, 0); + g.drawString("RESCUE", g.getWidth()/2, 70); + g.drawString("BREATHS", g.getWidth()/2, 120); + } +} + +function tick() { + provideFeedback(); + updateScreen(); + if (counter == 0) { + var reset = function() { + counter = setting('compression_count'); + clearInterval(interval); + interval = setInterval(tick, 60000/setting('compression_rpm')); + }; + clearInterval(interval); + interval = setInterval(reset, setting('breath_period_sec')*1000); + } + counter -= 1; +} + +interval = setInterval(tick, 60000/setting('compression_rpm')); + +g.clear(1).setFont("6x8"); +g.drawString(setting('compression_count') + ' / ' + setting('breath_count'), 30, 200); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); diff --git a/apps/cprassist/settings.js b/apps/cprassist/settings.js new file mode 100644 index 000000000..5776baa0b --- /dev/null +++ b/apps/cprassist/settings.js @@ -0,0 +1,64 @@ +// This file should contain exactly one function, which shows the app's settings +/** + * @param {function} back Use back() to return to settings menu + */ +(function(back) { + const SETTINGS_FILE = 'cprassist.settings.json'; + + // initialize with default settings... + let s = { + 'compression_count': 30, + 'breath_count': 2, + 'compression_rpm': 100, + 'breath_period_sec': 4 + }; + // ...and overwrite them with any saved values + // This way saved values are preserved if a new version adds more settings + const storage = require('Storage'); + const saved = storage.readJSON(SETTINGS_FILE, 1) || {}; + for (const key in saved) { + s[key] = saved[key]; + } + + // creates a function to safe a specific setting + function save(key) { + return function(value) { + s[key] = value; + storage.write(SETTINGS_FILE, s); + }; + } + + const menu = { + '': { 'title': 'CPR Assist' }, + '< Back': back, + 'chest compr.': { + value: s.compression_count, + min: 1, + max: 200, + step: 1, + onchange: save('compression_count'), + }, + 'rescue breaths': { + value: s.breath_count, + min: 0, + max: 100, + step: 1, + onchange: save('breath_count'), + }, + 'rpm': { + value: s.compression_rpm, + min: 1, + max: 200, + step: 10, + onchange: save('compression_rpm'), + }, + 'breaths period': { + value: s.breath_period_sec, + min: 1, + max: 60, + step: 1, + onchange: save('breath_period_sec'), + } + }; + E.showMenu(menu); +}); diff --git a/apps/cscsensor/ChangeLog b/apps/cscsensor/ChangeLog new file mode 100644 index 000000000..7be2ed3e2 --- /dev/null +++ b/apps/cscsensor/ChangeLog @@ -0,0 +1,5 @@ +0.01: New app! +0.02: Add wheel circumference settings dialog +0.03: Save total distance traveled +0.04: Add sensor battery level indicator + diff --git a/apps/cscsensor/README.md b/apps/cscsensor/README.md new file mode 100644 index 000000000..8ba862241 --- /dev/null +++ b/apps/cscsensor/README.md @@ -0,0 +1,16 @@ +# CSCSensor + +Simple app that can read a cycling speed and cadence (CSC) sensor and display the information on the watch. +Currently the app displays the following data: + +- moving time +- current speed +- average speed +- maximum speed +- trip distance traveled +- total distance traveled + +Button 1 resets all measurements except total distance traveled. The latter gets preserved by being written to storage every 0.1 miles and upon exiting the app. + +I do not have access to a cadence sensor at the moment, so only the speed part is currently implemented. Values displayed are imperial or metric (depending on locale), +the wheel circumference can be adjusted in the global settings app. diff --git a/apps/cscsensor/cscsensor-icon.js b/apps/cscsensor/cscsensor-icon.js new file mode 100644 index 000000000..12c597956 --- /dev/null +++ b/apps/cscsensor/cscsensor-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AH/OAAIuuGFYuEGFQv/ADOlwV8wK/qwN8AAelGAguiFogACWsulFw6SERcwAFSISLnSMuAFZWCGENWllWLRSZC0vOAAovWmUslkyvbqJwIuHGC4uBAARiDdAwueL4YACMQLmfX5IAFqwwoMIowpMQ4wpGIcywDiYAA2IAAgwGq2kFwIvGC5YtPDJIuCF4gXPFxQHLF44XQFxAKOF4oXRBg4LOFwYvEEag7OBgReQNZzLNF5IXPBJlXq4vVC5Qv8R9TXQFwbvYJBgLlNbYXRBoYOEA44XfCAgAFCxgXYDI4VPC7IA/AH4A/AH4AWA")) diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js new file mode 100644 index 000000000..65b50dfe7 --- /dev/null +++ b/apps/cscsensor/cscsensor.app.js @@ -0,0 +1,177 @@ +var device; +var gatt; +var service; +var characteristic; + +const SETTINGS_FILE = 'cscsensor.json'; +const storage = require('Storage'); + +class CSCSensor { + constructor() { + this.movingTime = 0; + this.lastTime = 0; + this.lastBangleTime = Date.now(); + this.lastRevs = -1; + this.settings = storage.readJSON(SETTINGS_FILE, 1) || {}; + this.settings.totaldist = this.settings.totaldist || 0; + this.totaldist = this.settings.totaldist; + this.wheelCirc = (this.settings.wheelcirc || 2230)/25.4; + this.speedFailed = 0; + this.speed = 0; + this.maxSpeed = 0; + this.lastSpeed = 0; + this.qUpdateScreen = true; + this.lastRevsStart = -1; + this.qMetric = !require("locale").speed(1).toString().endsWith("mph"); + this.speedUnit = this.qMetric ? "km/h" : "mph"; + this.distUnit = this.qMetric ? "km" : "mi"; + this.distFactor = this.qMetric ? 1.609344 : 1; + this.batteryLevel = -1; + } + reset() { + this.settings.totaldist = this.totaldist; + storage.writeJSON(SETTINGS_FILE, this.settings); + this.maxSpeed = 0; + this.movingTime = 0; + this.lastRevsStart = this.lastRevs; + this.maxSpeed = 0; + } + setBatteryLevel(level) { + this.batteryLevel = level; + } + updateScreen() { + var dist = this.distFactor*(this.lastRevs-this.lastRevsStart)*this.wheelCirc/63360.0; + var ddist = Math.round(100*dist)/100; + var tdist = Math.round(this.distFactor*this.totaldist*10)/10; + var dspeed = Math.round(10*this.distFactor*this.speed)/10; + var dmins = Math.floor(this.movingTime/60).toString(); + if (dmins.length<2) dmins = "0"+dmins; + var dsecs = (Math.floor(this.movingTime) % 60).toString(); + if (dsecs.length<2) dsecs = "0"+dsecs; + var avespeed = (this.movingTime>2 ? Math.round(10*dist/(this.movingTime/3600))/10 : 0); + var maxspeed = Math.round(10*this.distFactor*this.maxSpeed)/10; + for (var i=0; i<6; ++i) { + if ((i&1)==0) g.setColor(0, 0, 0); + else g.setColor(0.2, 0.1, 0.4); + g.fillRect(0, 48+i*32, 86, 48+(i+1)*32); + if ((i&1)==1) g.setColor(0, 0, 0); + else g.setColor(0.2, 0.1, 0.4); + g.fillRect(87, 48+i*32, 239, 48+(i+1)*32); + g.setColor(0.5, 0.5, 0.5).drawRect(87, 48+i*32, 239, 48+(i+1)*32).drawLine(0, 239, 239, 239).drawRect(0, 48, 87, 239); + } + g.setFontAlign(1, 0, 0).setFontVector(19).setColor(1, 1, 0); + g.drawString("Time:", 87, 66); + g.drawString("Speed:", 87, 98); + g.drawString("Ave spd:", 87, 130); + g.drawString("Max spd:", 87, 162); + g.drawString("Trip:", 87, 194); + g.drawString("Total:", 87, 226); + g.setFontAlign(-1, 0, 0).setFontVector(26).setColor(1, 1, 1);//.clearRect(92, 60, 239, 239); + g.drawString(dmins+":"+dsecs, 92, 66); + g.drawString(dspeed+" "+this.speedUnit, 92, 98); + g.drawString(avespeed + " " + this.speedUnit, 92, 130); + g.drawString(maxspeed + " " + this.speedUnit, 92, 162); + g.drawString(ddist + " " + this.distUnit, 92, 194); + g.drawString(tdist + " " + this.distUnit, 92, 226); + if (this.batteryLevel!=-1) { + g.setColor(1, 1, 1).drawRect(10, 55, 20, 75).fillRect(14, 53, 16, 55); + if (this.batteryLevel<25) g.setColor(1, 0, 0); + else if (this.batteryLevel<50) g.setColor(1, 0.5, 0); + else g.setColor(0, 1, 0); + g.fillRect(11, 74-18*this.batteryLevel/100, 19, 74); + console.log(this.batteryLevel); + this.batteryLevel = -1; + } + } + updateSensor(event) { + var qChanged = false; + if (event.target.uuid == "0x2a5b") { + var wheelRevs = event.target.value.getUint32(1, true); + var dRevs = (this.lastRevs>0 ? wheelRevs-this.lastRevs : 0); + if (dRevs>0) { + qChanged = true; + this.totaldist += dRevs*this.wheelCirc/63360.0; + if ((this.totaldist-this.settings.totaldist)>0.1) { + this.settings.totaldist = this.totaldist; + storage.writeJSON(SETTINGS_FILE, this.settings); + } + } + this.lastRevs = wheelRevs; + if (this.lastRevsStart<0) this.lastRevsStart = wheelRevs; + var wheelTime = event.target.value.getUint16(5, true); + var dT = (wheelTime-this.lastTime)/1024; + var dBT = (Date.now()-this.lastBangleTime)/1000; + this.lastBangleTime = Date.now(); + if (dT<0) dT+=64; + if (Math.abs(dT-dBT)>2) dT = dBT; + this.lastTime = wheelTime; + this.speed = this.lastSpeed; + if (dRevs>0 && dT>0) { + this.speed = (dRevs*this.wheelCirc/63360.0)*3600/dT; + this.speedFailed = 0; + this.movingTime += dT; + } + else { + this.speedFailed++; + qChanged = false; + if (this.speedFailed>3) { + this.speed = 0; + qChanged = (this.lastSpeed>0); + } + } + this.lastSpeed = this.speed; + if (this.speed > this.maxSpeed) this.maxSpeed = this.speed; + } + if (qChanged && this.qUpdateScreen) this.updateScreen(); + } +} + +var mySensor = new CSCSensor(); + +function getSensorBatteryLevel(gatt) { + gatt.getPrimaryService("180f").then(function(s) { + return s.getCharacteristic("2a19"); + }).then(function(c) { + return c.readValue(); + }).then(function(d) { + mySensor.setBatteryLevel(d.buffer[0]); + }); +} + +function parseDevice(d) { + device = d; + g.clearRect(0, 60, 239, 239).setFontAlign(0, 0, 0).setColor(0, 1, 0).drawString("Found device", 120, 120).flip(); + device.gatt.connect().then(function(ga) { + gatt = ga; + g.clearRect(0, 60, 239, 239).setFontAlign(0, 0, 0).setColor(0, 1, 0).drawString("Connected", 120, 120).flip(); + return gatt.getPrimaryService("1816"); +}).then(function(s) { + service = s; + return service.getCharacteristic("2a5b"); +}).then(function(c) { + characteristic = c; + characteristic.on('characteristicvaluechanged', (event)=>mySensor.updateSensor(event)); + return characteristic.startNotifications(); +}).then(function() { + console.log("Done!"); + g.clearRect(0, 60, 239, 239).setColor(1, 1, 1).flip(); + getSensorBatteryLevel(gatt); + mySensor.updateScreen(); +}).catch(function(e) { + g.clearRect(0, 60, 239, 239).setColor(1, 0, 0).setFontAlign(0, 0, 0).drawString("ERROR"+e, 120, 120).flip(); + console.log(e); +})} + +function connection_setup() { + NRF.setScan(parseDevice, { filters: [{services:["1816"]}], timeout: 2000}); + g.clearRect(0, 60, 239, 239).setFontVector(18).setFontAlign(0, 0, 0).setColor(0, 1, 0); + g.drawString("Scanning for CSC sensor...", 120, 120); +} + +connection_setup(); +setWatch(function() { mySensor.reset(); g.clearRect(0, 60, 239, 239); mySensor.updateScreen(); }, BTN1, {repeat:true, debounce:20}); +E.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect(); mySensor.settings.totaldist = mySensor.totaldist; storage.writeJSON(SETTINGS_FILE, mySensor.settings); }); +NRF.on('disconnect', connection_setup); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); diff --git a/apps/cscsensor/icons8-cycling-48.png b/apps/cscsensor/icons8-cycling-48.png new file mode 100644 index 000000000..0bc83859f Binary files /dev/null and b/apps/cscsensor/icons8-cycling-48.png differ diff --git a/apps/cscsensor/settings.js b/apps/cscsensor/settings.js new file mode 100644 index 000000000..d7a7d565d --- /dev/null +++ b/apps/cscsensor/settings.js @@ -0,0 +1,45 @@ +// This file should contain exactly one function, which shows the app's settings +/** + * @param {function} back Use back() to return to settings menu + */ +(function(back) { + const SETTINGS_FILE = 'cscsensor.json' + // initialize with default settings... + let s = { + 'wheelcirc': 2230, + } + // ...and overwrite them with any saved values + // This way saved values are preserved if a new version adds more settings + const storage = require('Storage') + const saved = storage.readJSON(SETTINGS_FILE, 1) || {} + for (const key in saved) { + s[key] = saved[key]; + } + // creates a function to safe a specific setting, e.g. save('color')(1) + function save(key) { + return function (value) { + s[key] = value; + storage.write(SETTINGS_FILE, s); + } + } + const menu = { + '': { 'title': 'Cycle speed sensor' }, + '< Back': back, + 'Wheel circ.(mm)': { + value: s.wheelcirc, + min: 800, + max: 2400, + step: 5, + onchange: save('wheelcirc'), + }, + 'Reset total distance': function() { + E.showPrompt("Zero total distance?", {buttons: {"No":false, "Yes":true}}).then(function(v) { + if (v) { + s['totaldist'] = 0; + storage.write(SETTINGS_FILE, s); + } + }).then(back); + } + } + E.showMenu(menu); +}) diff --git a/apps/cube/cube-icon.js b/apps/cube/cube-icon.js index 5ff0a2154..72a4ba4d9 100644 --- a/apps/cube/cube-icon.js +++ b/apps/cube/cube-icon.js @@ -1 +1 @@ - require("heatshrink").decompress(atob("/4AYv4CB+YdZABPvEkYA/AGv3EkfPAQP+DrI")) +require("heatshrink").decompress(atob("/4AYv4CB+YdZABPvEkYA/AGv3EkfPAQP+DrI")) diff --git a/apps/cube/cube.js b/apps/cube/cube.js index 7e0e70edf..426171469 100644 --- a/apps/cube/cube.js +++ b/apps/cube/cube.js @@ -2,9 +2,9 @@ var rx = 0, ry = 0; function draw() { var rcx=Math.cos(rx), - rsx=Math.sin(rx), - rcy=Math.cos(ry), - rsy=Math.sin(ry); + rsx=Math.sin(rx), + rcy=Math.cos(ry), + rsy=Math.sin(ry); function p(x,y,z) { var t; t = x*rcy + z*rsy; diff --git a/apps/custom/ChangeLog b/apps/custom/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/custom/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/custom/custom.html b/apps/custom/custom.html index 5a5dbbecd..684f813ae 100644 --- a/apps/custom/custom.html +++ b/apps/custom/custom.html @@ -7,7 +7,7 @@ - + diff --git a/apps/dane/app.js b/apps/dane/app.js index dc6262c58..5f7a48fbc 100644 --- a/apps/dane/app.js +++ b/apps/dane/app.js @@ -110,8 +110,8 @@ function drawTimeText() { var time = da[4].split(":"); var hours = time[0], - minutes = time[1], - seconds = time[2]; + minutes = time[1], + seconds = time[2]; g.setColor(mainColor); g.setFont(font, timeFontSize); g.drawString(`${hours}:${minutes}:${seconds}`, xyCenter, yposTime, true); diff --git a/apps/daysl/widget.js b/apps/daysl/widget.js index 4a32d5f26..4edbc3230 100644 --- a/apps/daysl/widget.js +++ b/apps/daysl/widget.js @@ -7,7 +7,7 @@ var debug = 0; //1 = show debug info //write settings to file function updateSettings() { - storage.write('daysleft.json', settings); + storage.write('daysleft.json', settings); } //Define standard settings @@ -24,8 +24,8 @@ settings = storage.readJSON('daysleft.json',1); //read storage if (!settings) resetSettings(); //if settings file was not found, set to standard var dd = settings.day, - mm = settings.month-1, //-1 because month is zero-based - yy = settings.year; + mm = settings.month-1, //-1 because month is zero-based + yy = settings.year; const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds const targetDate = new Date(yy, mm, dd); //is 00:00 diff --git a/apps/demoapp/ChangeLog b/apps/demoapp/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/demoapp/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/demoapp/app.js b/apps/demoapp/app.js index cb3136196..13c043587 100644 --- a/apps/demoapp/app.js +++ b/apps/demoapp/app.js @@ -27,22 +27,22 @@ var scenes = [ "| __|_ -| . | _| | | | | . |\n"+ "|____|___| _|_| |___|_|_|_|___|\n"+ " |_| espruino.com\n\n", - "The JavaScript Interpreter for uCs\n", - " * On-chip JS Interpreter", - " * GPS, Acclerometer, Compass", - " * 64 MHz, 64kB RAM, 512kB + 4MB Flash", - " * 240x240 IPS LCD", - " * Speaker & Vibration motor", - " * Bluetooth LE", - " * 1 week battery life", - "", - "Includes:", - " * Tensorflow AI", - " * Bluetooth LE central & periph", - " * Graphics Library", - " * VT100 terminal", - "","","" - ]; + "The JavaScript Interpreter for uCs\n", + " * On-chip JS Interpreter", + " * GPS, Acclerometer, Compass", + " * 64 MHz, 64kB RAM, 512kB + 4MB Flash", + " * 240x240 IPS LCD", + " * Speaker & Vibration motor", + " * Bluetooth LE", + " * 1 week battery life", + "", + "Includes:", + " * Tensorflow AI", + " * Bluetooth LE central & periph", + " * Graphics Library", + " * VT100 terminal", + "","","" + ]; var n=0; var i = setInterval(function() { Terminal.println(txt[n]); @@ -62,19 +62,19 @@ var scenes = [ function() { var img = require("heatshrink").decompress(atob("oNBxH+5wA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AHGpAAoQKv4ADCBQAeqsrAAejBw9/B4oABqt/IGepHw5CEQspALH5hBC5pAvv4/MAALFkIBWpPI6IHqpAu0Z3GfYOpRYdPQEhALYIp2FBYNVI4JAvvL4LH0yBYAFJAQQQ5Ay1JAFftBAQBYxCDv+qIGiCHIQiGnIBfOv5BJIQRAyIJkrvKEkIBrFBB4qEGIGRCNYsZAQIQV/IZDEiICRCDQVJAUIQVPC4lVIF6yJQYpAZ5t/FYvNIBepqtVIJGjIDoqBDY2pdYo3DfAhBIQLmpvIcDvIrC5oJEIAhTCGQmj5qgEC4t5e7YrBqt5BI6UFBg15v4XHbQwAQb4oAKv7NKABdVRoYATUAwnICqjZFIMdVE4+jXI4XGYCxBFFZN/M5OpCxUrvJ/ZFYmjvNVAAY+KCwpDBC6YAV5vNC9oA/AH4A/AHYA==")); - g.clear(); - y = 0; - var step = 4; - var i = setInterval(function() { - y+=step; g.clear(); - g.drawImage(img,60,60,{rotate:Math.sin(y*0.03)*0.5}); - g.flip(); - }, 20); - Bangle.setLCDMode("120x120"); - return function() { - if (i) clearInterval(i); - }; + y = 0; + var step = 4; + var i = setInterval(function() { + y+=step; + g.clear(); + g.drawImage(img,60,60,{rotate:Math.sin(y*0.03)*0.5}); + g.flip(); + }, 20); + Bangle.setLCDMode("120x120"); + return function() { + if (i) clearInterval(i); + }; }, function() { var rx = 0, ry = 0; @@ -82,9 +82,9 @@ var scenes = [ // draw a cube function draw() { var rcx=Math.cos(rx), - rsx=Math.sin(rx), - rcy=Math.cos(ry), - rsy=Math.sin(ry); + rsx=Math.sin(rx), + rcy=Math.cos(ry), + rsy=Math.sin(ry); // Project 3D coordinates into 2D function p(x,y,z) { var t; @@ -149,7 +149,7 @@ var scenes = [ y+=step; g.scroll(0,1); g.drawImage(img,Math.random()*240,Math.random()*240, - {rotate:Math.random()*6.3, scale:0.5+Math.random()}); + {rotate:Math.random()*6.3, scale:0.5+Math.random()}); }, 1); Bangle.setLCDMode(); return function() { diff --git a/apps/dotmatrixclock/ChangeLog b/apps/dotmatrixclock/ChangeLog new file mode 100644 index 000000000..7ab9e14a9 --- /dev/null +++ b/apps/dotmatrixclock/ChangeLog @@ -0,0 +1 @@ +0.01: Create dotmatrix clock app diff --git a/apps/dotmatrixclock/README.md b/apps/dotmatrixclock/README.md new file mode 100644 index 000000000..3af48efc6 --- /dev/null +++ b/apps/dotmatrixclock/README.md @@ -0,0 +1,28 @@ +# Dotmatrix clock + +A clock face simulating the classic dotmatrix displays. Shows time, date, compass, and heart rate. + +![](dotmatrix-clock-screen-shot.png) + +## Features + +* Easy to read digits +* Simulated white-on-blue dotmatrix display +* Compass +* Heart rate monitor +* Multiple colour palletes, swipe to change + +## Usage + +### Sensor readings + +When the display is activated by 'flipping' the watch up, the compass and heart sensors will be activated automatically, but if +you activate the LCD through a button press, then the sensors will remain off until you press button-1. + +### Colours + +The display defaults to blue, but you can change this to orange by swiping the screen + +## Requests + +If you have any feature requests, please send an email to the author paulcockrell@gmail.com` diff --git a/apps/dotmatrixclock/app.js b/apps/dotmatrixclock/app.js new file mode 100755 index 000000000..ba34d4885 --- /dev/null +++ b/apps/dotmatrixclock/app.js @@ -0,0 +1,354 @@ +/** + * BangleJS DotMatrixCLOCK + * + * + Original Author: Paul Cockrell https://github.com/paulcockrell + * + Created: May 2020 + */ +const storage = require('Storage'); +const settings = (storage.readJSON('setting.json', 1) || {}); +const is12Hour = settings["12hour"] || false; +const timeout = settings.timeout || 20; + +const font7x7 = { + "empty": "00000000", + "0": "3E61514945433E", + "1": "1808080808081C", + "2": "7E01013E40407F", + "3": "7E01013E01017E", + "4": "4141417F010101", + "5": "7F40407E01017E", + "6": "3E40407E41413E", + "7": "3F010202040408", + "8": "3E41413E41413E", + "9": "3E41413F01013E", +}; + +const font5x5 = { + "empty": "00000000", + "-": "0000FF0000", + "0": "0E1915130E", + "1": "0C0404040E", + "2": "1E010E101F", + "3": "1E010E011E", + "4": "11111F0101", + "5": "1F101E011E", + "6": "0E101E110E", + "7": "1F01020408", + "8": "0E110E110E", + "9": "0E110F010E", + "A": "040A0E1111", + "B": "1E111E111E", + "C": "0F1010100F", + "D": "1E1111111E", + "E": "1F101E101F", + "F": "1F101E1010", + "G": "0F1013110E", + "H": "11111F1111", + "I": "0E0404040E", + "J": "1F0404140C", + "L": "101010101F", + "M": "111B151111", + "N": "1119151311", + "O": "0E1111110E", + "P": "1E111E1010", + "R": "1E111E1111", + "S": "0F100E011E", + "T": "1F04040404", + "U": "111111110E", + "V": "1111110A04", + "W": "111115150A", + "Y": "110A040404", +}; + +// Char renderer +const COLORS = { + blue: { + BG: "#0297fe", + DARK: "#3b3ce8", + LIGHT: "#E9ffff", + }, + orange: { + BG: "#f7b336", + DARK: "#ac721e", + LIGHT: "#f6fc0f", + } +}; + +let selectedColor = "blue"; +let displayTimeoutRef, sensorTimeoutRef; + +// Example +// binToHex(["0111110", "1000000", "1000000", "1111110", "1000001", "1000001", "0111110"]) +function binToHex(bins) { + return bins.map(bin => ("00" + (parseInt(bin, 2).toString(16))).substr(-2).toUpperCase()).join(""); +} + +// Example +// hexToBin("3E40407E41413E") +function hexToBin(hexStr) { + const regEx = new RegExp("..", "g"); + const bin = hexStr + .replace(regEx, el => el + '_') + .slice(0, -1) + .split('_') + .map(hex => ("00000000" + (parseInt(hex, 16)).toString(2)).substr(-8)); + + return bin; +} + +function drawPixel(opts) { + g.setColor(opts.color); + g.fillRect(opts.x, opts.y, opts.x + opts.w, opts.y + opts.h); +} + +function drawGrid(pos, dims, charAsBin, opts) { + const defaultOpts = { + pxlW: 5, + pxlH: 5, + gap: 1, + offColor: COLORS[selectedColor].DARK, + onColor: COLORS[selectedColor].LIGHT + }; + const pxl = Object.assign({}, defaultOpts, opts); + + for (let rowY = 0; rowY < dims.rows; rowY++) { + const y = pos.y + ((pxl.pxlH + pxl.gap) * rowY); + + for (let colX = 7; colX > (7 - dims.cols); colX--) { + const x = pos.x + ((pxl.pxlW + pxl.gap) * colX); + const color = (charAsBin && parseInt(charAsBin[rowY][colX])) ? pxl.onColor : pxl.offColor; + + drawPixel({ + x: x, + y: y, + w: pxl.pxlW, + h: pxl.pxlH, + color: color, + }); + } + } +} + +function drawFont(str, font, x, y) { + let fontMap, rows, cols; + + switch(font) { + case "7x7": + fontMap = font7x7; + rows = cols = 7; + break; + case "5x5": + fontMap = font5x5; + rows = cols = 5; + break; + default: + throw "Unknown font type: " + font; + } + + const pxlW = 2; + const pxlH = 2; + const gap = 2; + const gutter = 3; + const charArr = str.split(""); + const gridWidthTotal = (rows * (pxlW + gap)) + gutter; + for (let i = 0; i < charArr.length; i++) { + const charAsBin = fontMap.hasOwnProperty(charArr[i])? + hexToBin(fontMap[charArr[i]]): + fontMap.empty; + + drawGrid( + {x: x + (i * gridWidthTotal), y: y}, + {rows: rows, cols: cols}, + charAsBin, + {pxlW: pxlW, pxlH: pxlH, gap: gap} + ); + } +} + +function drawTitles() { + g.setColor("#ffffff"); + g.setFont("6x8"); + g.drawString("COMPASS", 52, 49); + g.drawString("HEART", 122, 49); + g.drawString("TIME", 52, 94); + g.drawString("DATE", 52, 144); +} + +function drawCompass(lastHeading) { + const directions = [ + 'N', + 'NE', + 'E', + 'SE', + 'S', + 'SW', + 'W', + 'NW' + ]; + const cps = Bangle.getCompass(); + let angle = cps.heading; + let heading = angle? + directions[Math.round(((angle %= 360) < 0 ? angle + 360 : angle) / 45) % 8]: + "-- "; + + heading = (heading + " ").slice(0, 3); + if (lastHeading != heading) drawFont(heading, "5x5", 40, 67); + setTimeout(drawCompass.bind(null, heading), 1000 * 2); +} + +function drawHeart(hrm) { + drawFont((" " + (hrm ? hrm.bpm : "---")).slice(-3), "5x5", 109, 67); +} + +function drawTime(lastHrs, lastMns, toggle) { + const date = new Date(); + const h = date.getHours(); + const hrs = ("00" + ((is12Hour && h > 12) ? h - 12 : h)).substr(-2); + const mns = ("00" + date.getMinutes()).substr(-2); + + if (lastHrs != hrs) { + drawFont(hrs, "7x7", 48, 109); + } + if (lastMns != mns) { + drawFont(mns, "7x7", 124, 109); + } + + const color = toggle? COLORS[selectedColor].LIGHT : COLORS[selectedColor].DARK; + + // This should toggle on/off per second + drawPixel({ + color: color, + x: 118, y: 118, + w: 2, h: 2, + }); + drawPixel({ + color: color, + x: 118, y: 125, + w: 2, h: 2, + }); + + setTimeout(drawTime.bind(null, hrs, mns, !toggle), 1000); +} + +function drawDate(lastDate) { + const locale = require('locale'); + const date = new Date(); + + if (lastDate != date.toISOString().split('T')[0]) { + const dow = locale.dow(date, 1).toUpperCase(); + const dayNum = ("00" + date.getDate()).slice(-2); + const mon = locale.month(date).toUpperCase().slice(0, 3); + const yr = date.getFullYear().toString().slice(-2); + drawFont(dow + " " + dayNum, "5x5", 40, 159); + drawFont(mon + " " + yr, "5x5", 40, 189); + } + + setTimeout(drawDate.bind(null, date.toISOString().split('T')), 1000 * 60); +} + +function setSensors(state) { + // Already reading sensors and trying to activate sensors, do nothing + if (sensorTimeoutRef && state === 1) return; + + // If we are activating the sensors, turn them off again in one minute + if (state === 1) { + sensorTimeoutRef = setTimeout(() => { setSensors(0); }, 1000 * 60); + } else { + if (sensorTimeoutRef) { + clearInterval(sensorTimeoutRef); + sensorTimeoutRef = null; + } + // Bit nasty, but we only redraw the heart value on sensor callback + // but we want to blank out when sensor is off, but no callback for + // that so force redraw here + drawHeart(); + } + + Bangle.setHRMPower(state); + Bangle.setCompassPower(state); +} + +function drawScreen() { + g.setBgColor(COLORS[selectedColor].BG); + g.clearRect(0, 24, g.getWidth(), g.getHeight()); + + // Draw components + drawTitles(); + drawCompass(); + drawHeart(); + drawTime(); + drawDate(); +} + +function clearTimers(){ + if (displayTimeoutRef) { + clearInterval(displayTimeoutRef); + displayTimeoutRef = null; + } + + if (sensorTimeoutRef) { + clearInterval(sensorTimeoutRef); + sensorTimeoutRef = null; + } +} + +function resetDisplayTimeout() { + if (displayTimeoutRef) clearInterval(displayTimeoutRef); + Bangle.setLCDPower(true); + + displayTimeoutRef = setTimeout(() => { + if (Bangle.isLCDOn()) Bangle.setLCDPower(false); + clearTimers(); + }, 1000 * timeout); +} + +// Turn sensors on +setSensors(1); + +// Reset screen +g.clear(); + +// Load and draw widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +// Draw screen +drawScreen(); +resetDisplayTimeout(); + +// Setup callbacks +Bangle.on('swipe', (sDir) => { + selectedColor = selectedColor === "blue" ? "orange" : "blue"; + resetDisplayTimeout(); + drawScreen(); +}); + +Bangle.on('HRM', drawHeart); + +setWatch(() => { + setSensors(1); + resetDisplayTimeout(); +}, BTN1, {repeat: true, edge: "falling"}); + +setWatch(() => { + setSensors(0); + clearTimers(); + Bangle.setLCDMode(); + Bangle.showLauncher(); +}, BTN2, {repeat: false, edge: "falling"}); + +Bangle.on('lcdPower', (on) => { + if(on) { + resetDisplayTimeout(); + } else { + clearTimers(); + setSensors(0); + } +}); + +Bangle.on('faceUp', (up) => { + if (up && !Bangle.isLCDOn()) { + setSensors(1); + resetDisplayTimeout(); + } +}); \ No newline at end of file diff --git a/apps/dotmatrixclock/dotmatrix-clock-screen-shot.png b/apps/dotmatrixclock/dotmatrix-clock-screen-shot.png new file mode 100755 index 000000000..e6218f4c9 Binary files /dev/null and b/apps/dotmatrixclock/dotmatrix-clock-screen-shot.png differ diff --git a/apps/dotmatrixclock/dotmatrixclock-icon.js b/apps/dotmatrixclock/dotmatrixclock-icon.js new file mode 100644 index 000000000..8773839e1 --- /dev/null +++ b/apps/dotmatrixclock/dotmatrixclock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AAmBAEgrFAAZelFo+s1krAEcAE4IuFHIIJBAEXXE4KSEF84nCF4WBgErBYoAfEoaTBF42zF8PXF5QNBi4AgMIYv/F9nX64CDAw4ACl8vBIgGGF/4AOEgKPfI4xfoF96P/R/6PdACAv/F/4v/F/4v/F8HX68Xl8vAwIDCBIQADBIQQDBoQQDF/4AOGQqPbLAxmGL5gGDF/4AfF/6PRBIQQDSwwv/ABwoCR7xYGMwxfhF94AeF/4vr1nXBoIAf64mCF4gJEF8IkCF4YABFYQLDAEItBwIuCF9InBF4iSBwMrAEgnBFwgACXsIADFo4ABqwAkFQg=")) diff --git a/apps/dotmatrixclock/dotmatrixclock.png b/apps/dotmatrixclock/dotmatrixclock.png new file mode 100755 index 000000000..ab2637520 Binary files /dev/null and b/apps/dotmatrixclock/dotmatrixclock.png differ diff --git a/apps/espruinoctrl/ChangeLog b/apps/espruinoctrl/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/espruinoctrl/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/espruinoctrl/README.md b/apps/espruinoctrl/README.md new file mode 100644 index 000000000..a7bca662c --- /dev/null +++ b/apps/espruinoctrl/README.md @@ -0,0 +1,28 @@ +# Espruino Control + +Send commands to other Espruino devices via the Bluetooth UART interface. + +## Customising + +Click the customise button and you can customise your commands +with 4 options: + + +* **Title** - The title of the menu item that will be displayed +* **Command** - The JS command to execute, eg. `LED.toggle()` +* **MAC Address** - If specified, of the form `aa:bb:cc:dd:ee:ff`. The device +with this address will be connected to directly. If not specified a menu +showing available Espruino devices is popped up. +* **RX** - If checked, the app will display any data received from the +device being connected to. Use this if you want to print data - eg: `print(E.getBattery())` + +When done, click 'Upload'. Your changes will be saved to local storage +so they'll be remembered next time you upload from the same device.s + +## Usage + +Simply load the app and you'll see a menu with the menu items +you defined. Select one and you'll be able to connect to the device +and send the command. + +If a command should wait for a response then diff --git a/apps/espruinoctrl/app-icon.js b/apps/espruinoctrl/app-icon.js new file mode 100644 index 000000000..70d2dd062 --- /dev/null +++ b/apps/espruinoctrl/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwhH+AH4A/AH4A/AH4AFwIuuAAIllAAYIGF041IF34AKqwuuAANXF9QuCAANdGHqQgGBwvdGCIud5mjGB4udAAIwPFz3MSR61VFxQwNci4vGeh4uXGAguHGBK3WGA4AIegtXc69dGBxoBGAouWO4IwNe4gwZa4YwLFwikEFzAwLFwwwCFzQwKFw68YGB4AdF5AwmF5IwlF5QwkF5Yw/F8IwEL9WBB4IuuADwuzGxAugFAgliGBYutAH4A/AH4A/ADA=")) diff --git a/apps/espruinoctrl/app.png b/apps/espruinoctrl/app.png new file mode 100644 index 000000000..900861e43 Binary files /dev/null and b/apps/espruinoctrl/app.png differ diff --git a/apps/espruinoctrl/custom.html b/apps/espruinoctrl/custom.html new file mode 100644 index 000000000..f8e7e38b9 --- /dev/null +++ b/apps/espruinoctrl/custom.html @@ -0,0 +1,275 @@ + + + + + + + + +

Enter the menu items you'd like to see appear in the app below. MAC Address is the MAC address + of the device to use. If it isn't specified then a menu will be presented showing available devices.

+
+ + + + + + + + + + + + +
TitleCommandMAC AddressRX
+
+

+ + + + + + diff --git a/apps/files/ChangeLog b/apps/files/ChangeLog index 8b7be7640..b4037a733 100644 --- a/apps/files/ChangeLog +++ b/apps/files/ChangeLog @@ -1 +1,5 @@ 0.02: Fix deletion of apps - now use files list in app.info (fix #262) +0.03: Add support for data files +0.04: Add functionality to sort apps manually or alphabetically ascending/descending. +0.05: Tweaks to help with memory usage +0.06: Reduce memory usage \ No newline at end of file diff --git a/apps/files/files.js b/apps/files/files.js index 4775d35d0..9e6c97702 100644 --- a/apps/files/files.js +++ b/apps/files/files.js @@ -1,9 +1,7 @@ -const storage = require('Storage'); +const store = require('Storage'); const boolFormat = (v) => v ? "On" : "Off"; -let m; - function showMainMenu() { const mainmenu = { '': { @@ -12,48 +10,104 @@ function showMainMenu() { 'Free': { value: undefined, format: (v) => { - return storage.getFree(); + return store.getFree(); }, onchange: () => {} }, 'Compact': () => { E.showMessage('Compacting...'); try { - storage.compact(); + store.compact(); } catch (e) { } - m = showMainMenu(); + showMainMenu(); }, - 'Apps': ()=> m = showApps(), + 'Apps': ()=> showApps(), + 'Sort Apps': () => showSortAppsMenu(), '< Back': ()=> {load();} }; - return E.showMenu(mainmenu); + E.showMenu(mainmenu); } -function eraseApp(app) { +function isGlob(f) { + return /[?*]/.test(f); +} + +function globToRegex(pattern) { + const ESCAPE = '.*+-?^${}()|[]\\'; + const regex = pattern.replace(/./g, c => { + switch (c) { + case '?': return '.'; + case '*': return '.*'; + default: return ESCAPE.includes(c) ? ('\\' + c) : c; + } + }); + return new RegExp('^'+regex+'$'); +} + +function eraseFiles(info) { + info.files.split(",").forEach(f=>store.erase(f)); +} + +function eraseData(info) { + if(!info.data) return; + const d=info.data.split(';'), + files=d[0].split(','), + sFiles=(d[1]||'').split(','); + let erase = f=>store.erase(f); + files.forEach(f=>{ + if (!isGlob(f)) erase(f); + else store.list(globToRegex(f)).forEach(erase); + }); + erase = sf=>store.open(sf,'r').erase(); + sFiles.forEach(sf=>{ + if (!isGlob(sf)) erase(sf); + else store.list(globToRegex(sf+'\u0001')) + .forEach(fs=>erase(fs.substring(0,fs.length-1))); + }); +} +function eraseApp(app, files,data) { E.showMessage('Erasing\n' + app.name + '...'); - app.files.split(",").forEach(f=>storage.erase(f)); + var info = store.readJSON(app.id + ".info", 1)||{}; + if (files) eraseFiles(info); + if (data) eraseData(info); +} +function eraseOne(app, files,data){ + E.showPrompt('Erase\n'+app.name+'?').then((v) => { + if (v) { + Bangle.buzz(100, 1); + eraseApp(app, files, data); + showApps(); + } else { + showAppMenu(app); + } + }); +} +function eraseAll(apps, files,data) { + E.showPrompt('Erase all?').then((v) => { + if (v) { + Bangle.buzz(100, 1); + apps.forEach(app => eraseApp(app, files, data)); + } + showApps(); + }); } function showAppMenu(app) { - const appmenu = { + let appmenu = { '': { 'title': app.name, }, - '< Back': () => m = showApps(), - 'Erase': () => { - E.showPrompt('Erase\n' + app.name + '?').then((v) => { - if (v) { - Bangle.buzz(100, 1); - eraseApp(app); - m = showApps(); - } else { - m = showAppMenu(app) - } - }); - } + '< Back': () => showApps(), }; - return E.showMenu(appmenu); + if (app.hasData) { + appmenu['Erase Completely'] = () => eraseOne(app, true, true); + appmenu['Erase App,Keep Data'] = () => eraseOne(app, true, false); + appmenu['Only Erase Data'] = () => eraseOne(app, false, true); + } else { + appmenu['Erase'] = () => eraseOne(app, true, false); + } + E.showMenu(appmenu); } function showApps() { @@ -61,30 +115,28 @@ function showApps() { '': { 'title': 'Apps', }, - '< Back': () => m = showMainMenu(), + '< Back': () => showMainMenu(), }; - var list = storage.list(/\.info$/).filter((a)=> { + var list = store.list(/\.info$/).filter((a)=> { return a !== 'setting.info'; - }).sort().map((app) => { - var ret = storage.readJSON(app,1)||{}; - ret[''] = app; - return ret; - }); + }).map((a)=> { + let app = store.readJSON(a, 1) || {}; + return {id: app.id, name: app.name, hasData: !!app.data}; + }).sort(sortHelper()); if (list.length > 0) { list.reduce((menu, app) => { - menu[app.name] = () => m = showAppMenu(app); + menu[app.name] = () => showAppMenu(app); return menu; }, appsmenu); appsmenu['Erase All'] = () => { - E.showPrompt('Erase all?').then((v) => { - if (v) { - Bangle.buzz(100, 1); - for (var n = 0; n < list.length; n++) - eraseApp(list[n]); - } - m = showApps(); + E.showMenu({ + '': {'title': 'Erase All'}, + 'Erase Everything': () => eraseAll(list, true, true), + 'Erase Apps,Keep Data': () => eraseAll(list, true, false), + 'Only Erase Data': () => eraseAll(list, false, true), + '< Back': () => showApps(), }); }; } else { @@ -94,7 +146,82 @@ function showApps() { onchange: ()=> {} }; } - return E.showMenu(appsmenu); + E.showMenu(appsmenu); } -m = showMainMenu(); +function showSortAppsMenu() { + const sorterMenu = { + '': { + 'title': 'App Sorter', + }, + '< Back': () => showMainMenu(), + 'Sort: manually': ()=> showSortAppsManually(), + 'Sort: alph. ASC': () => { + E.showMessage('Sorting:\nAlphabetically\nascending ...'); + sortAlphabet(false); + }, + 'Sort: alph. DESC': () => { + E.showMessage('Sorting:\nAlphabetically\ndescending ...'); + sortAlphabet(true); + } + }; + E.showMenu(sorterMenu); +} + +function showSortAppsManually() { + const appsSorterMenu = { + '': { + 'title': 'Sort: manually', + }, + '< Back': () => showSortAppsMenu(), + }; + let appList = getAppsList(); + if (appList.length > 0) { + appList.reduce((menu, app) => { + menu[app.name] = { + value: app.sortorder || 0, + min: 0, + max: appList.length, + step: 1, + onchange: val => setSortorder(app, val) + }; + return menu; + }, appsSorterMenu); + } else { + appsSorterMenu['...No Apps...'] = { + value: undefined, + format: ()=> '', + onchange: ()=> {} + }; + } + E.showMenu(appsSorterMenu); +} + +function setSortorder(app, val) { + app = store.readJSON(app.id + '.info', 1); + app.sortorder = val; + store.write(app.id + '.info', JSON.stringify(app)); +} + +function getAppsList() { + return store.list('.info').map((a)=> { + let app = store.readJSON(a, 1) || {}; + if (app.type !== 'widget') { + return {id: app.id, name: app.name, sortorder: app.sortorder}; + } + }).filter((a) => a).sort(sortHelper()); +} + +function sortAlphabet(desc) { + let appsSorted = desc ? getAppsList().reverse() : getAppsList(); + appsSorted.forEach((a, i) => { + setSortorder(a, i); + }); + showSortAppsMenu(); +} + +function sortHelper() { + return (a, b) => (a.name > b.name) - (a.name < b.name); +} + +showMainMenu(); diff --git a/apps/findphone/ChangeLog b/apps/findphone/ChangeLog new file mode 100644 index 000000000..9297fc6c7 --- /dev/null +++ b/apps/findphone/ChangeLog @@ -0,0 +1 @@ +0.01: First Version \ No newline at end of file diff --git a/apps/findphone/README.md b/apps/findphone/README.md new file mode 100644 index 000000000..870847222 --- /dev/null +++ b/apps/findphone/README.md @@ -0,0 +1,9 @@ +# Find Phone + +Ring your phone via GadgetBridge if you lost it somewhere. + +1. Enable HID in settings +2. Connect GadgetBridge +3. Lose phone +4. Open app +5. Click any button or screen diff --git a/apps/findphone/app-icon.js b/apps/findphone/app-icon.js new file mode 100644 index 000000000..95a73755e --- /dev/null +++ b/apps/findphone/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkCkQA/AEp0JCxkgC5KJMUpYXMgf/AA0wC5sPC4/wC/4XhxAXXwQXtlBIJC5URC4QwIC5PxFgQXT/QUCC6fwC4ZgIC5E/+EYCgJ4JC4/zwfwhAXTnGIC9pHXO66nY//4a63xFYTvUiJeCC6cAOxQXNFxIXllAWIC5oAKC+EDC48wC5oAKC9EBiAXokBGJgQXLMBQWMAH4AZA=")) \ No newline at end of file diff --git a/apps/findphone/app.js b/apps/findphone/app.js new file mode 100644 index 000000000..a532e3b50 --- /dev/null +++ b/apps/findphone/app.js @@ -0,0 +1,33 @@ +var storage = require('Storage'); + +//notify your phone +function find(){ + Bluetooth.println(JSON.stringify({t:"findPhone", n:true})); +} + +//init graphics +g.clear(); +require("Font8x12").add(Graphics); +g.setFont("8x12",3); +g.setFontAlign(0,0); +g.flip(); + +//init settings +const settings = storage.readJSON('setting.json',1) || { HID: false }; + +//check if HID enabled and show message +if (settings.HID=="kb" || settings.HID=="kbmedia") { + g.setColor(0x03E0); + g.drawString("click to find", g.getWidth()/2, g.getHeight()/2); + + //register all buttons and screen to find phone + setWatch(find, BTN1); + setWatch(find, BTN2); + setWatch(find, BTN3); + setWatch(find, BTN4); + setWatch(find, BTN5); + +}else{ + g.setColor(0xf800); + g.drawString("enable HID!", g.getWidth()/2, g.getHeight()/2); +} \ No newline at end of file diff --git a/apps/findphone/app.png b/apps/findphone/app.png new file mode 100644 index 000000000..70d891396 Binary files /dev/null and b/apps/findphone/app.png differ diff --git a/apps/flagrse/ChangeLog b/apps/flagrse/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/flagrse/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/flagrse/README.md b/apps/flagrse/README.md new file mode 100644 index 000000000..819ebde36 --- /dev/null +++ b/apps/flagrse/README.md @@ -0,0 +1,76 @@ +# Espruino Flag Raiser + +An app to send a command to another Espruino to cause it to raise a flag. + +For this to work, you need to upload the following code to another +bluetooth Espruino device (the one with the flag attached) : + +``` +var FLAG_PIN = D14; + +var s = require("servo").connect(FLAG_PIN); +s.move(1,3000); // move to position 1 over 3 seconds + +var timeout; +function flag() { + if (timeout) clearTimeout(); + s.move(0.2,2000); + timeout = setTimeout(function() { + timeout = undefined; + s.move(1,2000); + },2000); +} + +setWatch(flag, BTN, {repeat:true}); + +NRF.setServices({ + "3e440001-f5bb-357d-719d-179272e4d4d9": { + "3e440002-f5bb-357d-719d-179272e4d4d9": { + value : [0], + maxLen : 1, + writable : true, + onWrite : function(evt) { + flag(); + } + } + } +}, { uart : false }); +NRF.setAdvertising({}, {name:"Flag"}); +``` + +## Wiring + +This is designed for an [MDBT42Q Breakout board](http://www.espruino.com/MDBT42Q) +but should work on any Bluetooth LE Espruino device - you just need to change `FLAG_PIN` +to the name of the pin that's connected to the servo motor. + +However, as designed: + +* Get an [MDBT42Q Breakout board](http://www.espruino.com/MDBT42Q) +* Connect `GND` to GND (black) of a 3.7v LiPo battery +* Connect `Vin` to positive (red) of the battery +* Take a servo motor and: + * Connect the Black wire to `GND` (LiPo GND) + * Connect the Red wire to `Vin` (LiPo 3.7v) + * Connect the White wire to `D14` on the MDBT42Q + +## How does it work? + +The code above changes the advertised name of the Espruino device to be +`Flag` (which the app then searches for). + +Then, it adds a service UUID `3e440001-f5bb-357d-719d-179272e4d4d9` (this +is just a random number we made up) with characteristic `3e440002-f5bb-357d-719d-179272e4d4d9` +(the same UUID with the second 16 bits incremented). When the characteristic +is written (with any data), `flag()` is called, which raises the flag. + +`flag()` itself uses the [servo module](http://www.espruino.com/Servo+Motors) +to allow the servo motor to be controlled easily. + +You might find the [Espruino About Bluetooth LE page](http://www.espruino.com/About+Bluetooth+LE) +is useful as an introduction to services and characteristics. + +### Don't want to use a servo motor? + +No problem, just replace `flag()` with a function that controls whatever you need +it to. diff --git a/apps/flagrse/app.js b/apps/flagrse/app.js index e7e8e2445..e03e4fb07 100644 --- a/apps/flagrse/app.js +++ b/apps/flagrse/app.js @@ -5,15 +5,15 @@ function redraw() { g.drawImage(img, 120-96, 120-96, {scale:2}); } - // Code for button (Puck.js) - var busy = false; +// Code for button (Puck.js) +var busy = false; var lastTry = getTime(); function flag() { E.showMessage("Working..."); if (busy && lastTry+5bbot)) gameStop(); }); @@ -100,7 +101,7 @@ Bangle.on('touch', function(button) { if (!running) { gameStart(); } else { - birdvy -= 4; + birdvy -= 4; } }); diff --git a/apps/gallifr/ChangeLog b/apps/gallifr/ChangeLog new file mode 100644 index 000000000..c785cbd67 --- /dev/null +++ b/apps/gallifr/ChangeLog @@ -0,0 +1 @@ +0.01: First released version diff --git a/apps/gallifr/README.md b/apps/gallifr/README.md new file mode 100644 index 000000000..b88a3cb53 --- /dev/null +++ b/apps/gallifr/README.md @@ -0,0 +1,20 @@ +# Time Traveller's Clock + +The time travelling wristwatch is for those who are so attuned to the ebb and flow of time that they no longer require antiquated numbers to read the time. + +For those that need some tuition in the ways of the time traveller, the light coloured segment of the pie chart provides a traditional readout of minute. The black sphere that revolves around the edge of the display provides an indication of the hour. + +## Features + +The following aspects are customisable using the App Loader Menu system: + +1. Colour; the dial has four colour schemes: +- shades of green +- shades of red +- shades of blue +- a 1980's scheme +2. Widgets; these can be turned on or off - when turned off, the dial uses the whole screen and is slightly larger +3. Decoration; for those attuned to the time streams, the dial itself reads 'time'. For those who don't need to be reminded what the dial is for, this can be optionally turned off. + +## Code description +The code includes some functions that others may find useful in creating their own applications. These are explained in my robot-building blog [here](https://k9-build.blogspot.com/). \ No newline at end of file diff --git a/apps/gallifr/app-icon.js b/apps/gallifr/app-icon.js new file mode 100644 index 000000000..f0b27e1c8 --- /dev/null +++ b/apps/gallifr/app-icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("MDAIAAAAAAAAAAAAAAAABgYAAAAAAAYGDAwSGBgYGBISBgAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAwMEhISGBgYHh4eHh4eHhgSDAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABhgYEhIYGBgYEhIYHh4eHh4eHh4eHhgMAAAGAAAAAAAAAAAAAAAAAAAAAAAGAAASHh4eGBISEhISEhIYHh4eHh4eHh4eHh4eGAYABgAAAAAAAAAAAAAAAAAAAAYADBgeHh4eGBIYEhISEhIYHh4eHh4eHh4eHh4eHh4SAAYAAAAAAAAAAAAAAAAABgAMHh4eHh4eHhgSEhIYGBgYHh4eHh4eHh4eHh4eHh4eEgAGAAAAAAAAAAAAAAAGABIeHh4eHh4eHhgSGBgSEhIMEhgYHh4eHh4eHh4eHh4eHhIABgAAAAAAAAAAAAYAEh4eHh4eHh4eHh4SEgwAAAAAAAAAABIYHh4eHh4eHh4eHh4SAAYAAAAAAAAABgAMHh4eHh4eHh4eHhIGAAAMEhISGB4YEgAABhIeHh4eHh4eHh4eEgAGAAAAAAAAAAweHh4eHh4eHh4YDAAABhIYGBgYHh4eHhgGAAAMGB4eHh4eHh4eHhIABgAAAAAAABgeHh4eHh4eHhISGAAMGBgSEhIYHh4eHh4eDAASEgweHh4eHh4eHh4MAAAAAAYAEh4eHh4eHh4eBhIeDAAeHhISGBgYHh4eHh4eGAAGHhIAHh4eHh4eHh4YAAAAAAAGHh4eHh4eHh4GEh4YABgeHhgSEhIMEhgeHh4eHhgAEh4SBh4eHh4eHh4eEgAGBgAYHh4eHh4eHhISHh4MDB4eHhgSDAAAAAAMHh4eHh4AAB4eEgweHh4eHh4eHgAAAAYeHh4eHh4eGBIeHh4AEh4eHh4MABISGBgADB4eHh4SABgeHgwSHh4eHh4eHhIAABIeHh4eHh4eBh4eHhgAGB4eHhgADBgYHh4SABgeHh4YABgeHhgAHh4eHh4eHhgAABgeHh4eHh4SEh4eHhgAGB4eHhgAEhgYHh4YABgeHh4YABIeHh4MEh4eHh4eHh4MBh4eHh4eHh4MHh4eHhgAGB4eHhgAEhgYHh4YABgeHh4YABgeHh4YAB4eHh4eHh4SDB4eHh4eHhgSHh4eHhgAGB4eHh4ADBIYHh4MAB4eHh4YABgeHh4eDBIeHh4eHh4YEh4eHh4eHhIYHh4eHhgADB4eHh4YAAYSEgwAGB4eHh4SAAweHh4eEgYYHh4eHh4YGB4eHh4eHgwYHh4eHh4MAB4eHh4eGAYAAAYYHh4eHh4AEh4YGBgSAAAAABgeHh4eGB4eHh4eHgweHh4eHh4YABIeHh4eHh4YGB4eHh4eHhIAGB4eGAAAEgYSEgAYHh4eGB4eHh4eGBIeHh4eHh4eDAAYHh4eHh4eHh4eHh4eGAASHh4eGAAYHgwYHgYAHh4eGB4eHh4eGAweHh4eHh4MAAYAGB4eHh4eHh4eHh4YAAweHh4eEgAeHgwYHhIAGB4eHh4eHh4eGAweHh4eGAYMGB4MABIeHh4eHh4eHhIADB4eHh4eEgAeHgwYHhIAGB4eHh4eHh4eGAweHhgSEhgeHh4YAAAADBIYGBIMAAASHh4eHh4eGAAYHgweHgwGHh4eHh4eHh4eGAYeGBgeHh4eHh4MABgSDAAAAAAMEhgeHh4eHh4eHgwAEgwYEgAYHh4eGB4eHh4eGAAYHh4eHh4eHhgAGB4eHh4YGB4eHh4eHh4eHh4eHh4MAAAAABgeHh4YGB4eHh4YGAYSHh4eHh4eHgASHh4eHh4eHh4eHh4eHh4eHh4eHh4eEgwYHh4eHh4YEh4YEgwYHhIMHh4eHh4eDBIeHh4eHh4eHh4eHh4eHh4eHh4eHh4eEhgeHh4eHh4SDBIAEh4eHh4AGB4eHh4YEh4eHh4eHh4YGB4eHh4eHh4eHh4eHh4eDB4eHh4eHh4MAAwYHh4eHh4SDB4eHhgGEhgYHh4YEhgSEhgYGB4eHh4eHh4eHh4SEh4eHh4eHh4GABgeHh4eHh4eABgeDAAAAAAABgwYHh4eHh4eGBIYHh4eHh4eHh4GHh4eHh4eHhgAABIeHh4eHh4eGAwGAAYAAAYGAAASHh4eHh4eHh4SEh4eHh4eHhIYHh4eHh4eHhIAAAAYHh4eHh4eGAAABgAAAAAAAAYAEh4eHh4eHh4eGBIeHh4eEhIeHh4eHh4eGAAABgASHh4eHh4eDAAGAAAAAAAAAAAGABgeHh4eHh4eHhIYHh4SBh4eHh4eHh4eEgAGAAYAGB4eHh4YAAAAAAAAAAAAAAAGABIeHh4eHh4eHh4SHhIGHh4eHh4eHh4YAAAAAAAABh4eHh4YAAYAAAAAAAAAAAAGAAweHh4eHh4eHh4YDBIeHh4eHh4eHh4GAAAAAAAGABIeHh4MAAAAAAAAAAAAAAAGAAYeHh4eHh4eHh4SGB4eHh4eHh4eHhIABgAAAAAABgASHhIABgAAAAAAAAAAAAAGAAweHh4eHh4eHh4eHh4eHh4eHh4eEgAGAAAAAAAAAAAADAYSAAAAAAAAAAAAAAAGABIeHh4eHh4eHh4eHh4eHh4eHh4YAAAAAAAAAAAAAAAAABIeBgAGAAAAAAAAAAAGABgeHh4eHh4eHh4eHh4eHh4eHhgAAAAAAAAAAAAAAAAAAAAYGAAAAAAAAAAAAAYADB4eHh4eHh4eHh4eHh4eHh4eEgAAAAAAAAAAAAAAAAAAAAAAEgwAAAAABgYGBgAAGB4eHh4eHh4eHh4eHh4eHh4SAAAAAAAAAAAAAAAAAAAAAAAAAAYGAAAAAAAAAAweHh4eHh4eHh4eHh4eHh4eGAYABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAYMDAwSGB4eHh4eHh4eHh4eHh4eHhgSAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYMEhgeHh4eHh4eHh4eHh4eHh4YEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYMEhgYHh4eHh4eGBgSDAYAAAAGAAAAAAAAAAAAAAAA")) \ No newline at end of file diff --git a/apps/gallifr/app.js b/apps/gallifr/app.js new file mode 100644 index 000000000..281988ad7 --- /dev/null +++ b/apps/gallifr/app.js @@ -0,0 +1,247 @@ +// +// Time Travellers Watch +// Written May 2020 by Richard Hopkins +// based on a skeleton app by Gordon Williams +// +const locale = require('locale'); +let timer = null; +let currentDate = new Date(); +const cirRad = 2*Math.PI; +const proportion = 0.3; // relative size of hour hand +const thickness = 4; // thickness of decorative lines +// retrieve settings from menu +let settings = require('Storage').readJSON('gallifr.json',1)||{}; +const decoration = !settings.decoration; +const widgets = !settings.widgets; +if (widgets) { + widgetHeight = 24;} +else { + widgetHeight = 0;} +const colours = ["green","red","blue","80s"]; +const colour = colours[settings.colour]; +const centerX = Math.round(g.getWidth() / 2); +const centerY = widgetHeight + Math.round((g.getHeight()-widgetHeight) / 2); +const radius = Math.round(Math.min(g.getWidth()/2,(g.getHeight()-widgetHeight) / 2)); + +const drawSegment = (params) => { + angle1 = params.start/360*cirRad; + angle2 = (params.start + params.arc)/360*cirRad; + segRadius = Math.round(params.radius*radius); + x = centerX + (params.x * radius); + y = centerY - (params.y *radius); + g.setColor(0,0,0); + incr = cirRad/15; + for (i = angle1; i < angle2; i=i+incr) { + brush = thickness * (angle2-angle1) /angle2; + points = [ + x + Math.sin(i) * (segRadius+brush), + y - Math.cos(i) * (segRadius+brush), + x + Math.sin(i+incr) * (segRadius+brush), + y - Math.cos(i+incr) * (segRadius+brush), + x + Math.sin(i+incr) * (segRadius-brush), + y - Math.cos(i+incr) * (segRadius-brush), + x + Math.sin(i) * (segRadius-brush), + y - Math.cos(i) * (segRadius-brush) + ]; + g.fillPoly(points); + } +}; + +const drawThickLine = (params) => { + g.setColor(0,0,0); + from = { + x: centerX + (params.fromX * radius), + y: centerY - (params.fromY * radius) + }; + to = { + x: centerX + (params.toX * radius), + y: centerY - (params.toY * radius) + }; + vec = {}; + vec.x = to.x - from.x; + vec.y = to.y - from.y; + pVec = {}; + pVec.x = vec.y; + pVec.y = -vec.x; + length = Math.sqrt(pVec.x * pVec.x + pVec.y * pVec.y); + nVec = {}; + nVec.x = pVec.x / length; + nVec.y = pVec.y / length; + array = [ + from.x + nVec.x * thickness, + from.y + nVec.y * thickness, + from.x - nVec.x * thickness, + from.y - nVec.y * thickness, + to.x + nVec.x * thickness, + to.y + nVec.y * thickness, + to.x - nVec.x * thickness, + to.y - nVec.y * thickness + ]; + g.fillPoly(array); +}; + + + +const drawHands = () => { + drawMinuteHand(); + drawHourHand(); + if (decoration) { + drawDecoration(); + } +}; + +const drawDecoration = () => { + params = { + start: 210, + arc: 295, + radius: 0.7, + x: 0, + y: 0 + }; + drawSegment(params); + params = { + start: 290, + arc: 135, + radius: 0.4, + x: 0, + y: -0.7 + }; + drawSegment(params); + params = { + start: 0, + arc: 360, + radius: 0.4, + x: 0, + y: 0.3 + }; + drawSegment(params); + params = { + start: 0, + arc: 360, + radius: 0.15, + x: 0, + y: 0.3 + }; + drawSegment(params); + params = { + start: 0, + arc: 360, + radius: 0.15, + x: 0.7, + y: 0 + }; + drawSegment(params); + params = { + fromX: 0.4, + fromY: 0.2, + toX: 0.6, + toY: 0.1 + }; + drawThickLine(params); + params = { + fromX: -0.2, + fromY: -0.05, + toX: -0.7, + toY: -0.7 + }; + drawThickLine(params); + params = { + fromX: -0.3, + fromY: 0.05, + toX: -0.95, + toY: -0.3 + }; + drawThickLine(params); +}; + +const drawMinuteHand = () => { + angle = currentDate.getMinutes()/60 * cirRad; + //angle = currentDate.getSeconds()/60 * cirRad; + switch(colour) { + case "red": + g.setColor(1,0,0); + break; + case "green": + g.setColor(0,1,0); + break; + case "blue": + g.setColor(0,0,1); + break; + case "80s": + g.setColor(1,0,0); + break; + default: + g.setColor(0,1,0); + } + + var points = [centerX,centerY]; + for (i = 0; i < angle; i=i+cirRad/60) { + points.push(Math.round(centerX + Math.sin(i) * radius), + Math.round(centerY - Math.cos(i) * radius)); + } + g.fillPoly(points); +}; + +const drawHourHand = () => { + g.setColor(0,0,0); + //angle = currentDate.getMinutes()/60 * cirRad; + angle = currentDate.getHours()/12 * cirRad; + g.fillCircle( + Math.round(centerX + Math.sin(angle) * radius * (1-proportion)), + Math.round(centerY - Math.cos(angle) * radius * (1-proportion)), + radius * proportion + ); +}; + +const drawClockFace = () => { + switch(colour) { + case "red": + g.setColor(0.8,0.3,0); + break; + case "green": + g.setColor(0.1,0.7,0); + break; + case "blue": + g.setColor(0,0.3,0.8); + break; + case "80s": + g.setColor(1,1,1); + break; + default: + g.setColor(0.1,0.7,0); + } + g.fillCircle(centerX,centerY,radius*0.98); +}; + +const drawAll = () => { + currentDate = new Date(); + g.clear(); + if (widgets) {Bangle.drawWidgets();} + drawClockFace(); + drawHands(); +}; + + +const startTimers = () => { + //timer = setInterval(drawAll, 1000); + timer = setInterval(drawAll, 1000*20); +}; + +Bangle.on('lcdPower', (on) => { + if (on) { + startTimers(); + drawAll(); + } else { + if (timer) { + clearInterval(timer); + } + } +}); + +g.clear(); +startTimers(); +Bangle.loadWidgets(); +drawAll(); + +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); diff --git a/apps/gallifr/gallifr.png b/apps/gallifr/gallifr.png new file mode 100644 index 000000000..9bb50e3cd Binary files /dev/null and b/apps/gallifr/gallifr.png differ diff --git a/apps/gallifr/settings.js b/apps/gallifr/settings.js new file mode 100644 index 000000000..feb6b0ffc --- /dev/null +++ b/apps/gallifr/settings.js @@ -0,0 +1,33 @@ +// make sure to enclose the function in parentheses +(function (back) { + let settings = require('Storage').readJSON('gallifr.json',1)||{}; + let colours = ["green","red","blue","80s"]; + let onoff = ["on","off"]; + function save(key, value) { + settings[key] = value; + require('Storage').writeJSON('gallifr.json',settings); + } + const appMenu = { + '': {'title': 'Clock Settings'}, + '< Back': back, + 'Colour': { + value: 0|settings['colour'], + min:0,max:3, + format: m => colours[m], + onchange: m => {save('colour', m)} + }, + 'Widgets': { + value: 0|settings['widgets'], + min:0,max:1, + format: m => onoff[m], + onchange: m => {save('widgets', m)} + }, + 'Decoration': { + value: 0|settings['decoration'], + min:0,max:1, + format: m => onoff[m], + onchange: m => {save('decoration', m)} + } + }; + E.showMenu(appMenu) +}) diff --git a/apps/gbridge/ChangeLog b/apps/gbridge/ChangeLog index f23a4eb6d..9a3090f5d 100644 --- a/apps/gbridge/ChangeLog +++ b/apps/gbridge/ChangeLog @@ -9,3 +9,11 @@ 0.08: Don't turn on LCD at start of every song 0.09: Update Bluetooth connection state automatically 0.10: Make widget play well with other Gadgetbridge widgets/apps +0.11: Report battery status on connect and at regular intervals +0.12: Setting to show/hide icon +0.13: Modified to use the 'notify' library +0.14: Added 'find' event handling +0.15: Don't keep LCD on while playing music +0.16: Handle dismissing notifications on the phone + Nicer display of alarm clock notifications +0.17: Modified music notification for updated 'notify' library diff --git a/apps/gbridge/sample_messages.js b/apps/gbridge/sample_messages.js new file mode 100644 index 000000000..be33a25b8 --- /dev/null +++ b/apps/gbridge/sample_messages.js @@ -0,0 +1,21 @@ +/** + * Some sample messages to test Gadgetbridge notifications + */ +// send both of these to trigger music notification +GB({"t":"musicinfo","artist":"Some Artist Name","album":"The Album Name","track":"The Track Title Goes Here","dur":241,"c":2,"n":2}) +GB({"t":"musicstate","state":"play","position":0,"shuffle":1,"repeat":1}) + +// WhatsApp group +GB({"t":"notify","id":1592721712,"src":"WhatsApp","title":"Sample Group: Sam","body":"This is a test WhatsApp message"}) +GB({"t":"notify","id":1592721714,"src":"WhatsApp","title":"Sample Group (2 messages): Robin","body":"This is another test WhatsApp message"}) +GB({"t":"notify","id":1592721719,"src":"WhatsApp","title":"Sample Group (3 messages): Kim","body":"This is yet another test WhatsApp message, but it is really really really really really really long. Almost as if somebody wanted to test how much characters you could stuff into a notification before all of the body text just wouldn't fit anymore."}) + +// Alarm clock + dismissal +GB({"t":"notify","id":1592721714,"src":"ALARMCLOCKRECEIVER"}) +GB({"t":"notify-","id":1592721714}) + +// Weather update (doesn't show a notification, not handled by gbridge app: see weather app) +GB({"t":"weather","temp":288,"hum":94,"txt":"Light rain","wind":0,"loc":"Test City"}) + +// Nextcloud updated a file +GB({"t":"notify","id":1594184421,"src":"Nextcloud","title":"Downloaded","body":"test.file downloaded"}) diff --git a/apps/gbridge/settings.js b/apps/gbridge/settings.js index 723c9cae9..d1ecb594b 100644 --- a/apps/gbridge/settings.js +++ b/apps/gbridge/settings.js @@ -2,10 +2,33 @@ function gb(j) { Bluetooth.println(JSON.stringify(j)); } - + function settings() { + let settings = require('Storage').readJSON("gbridge.json", true) || {}; + if (!("showIcon" in settings)) { + settings.showIcon = true; + } + return settings + } + function updateSetting(setting, value) { + let settings = require('Storage').readJSON("gbridge.json", true) || {}; + settings[setting] = value + require('Storage').write('gbridge.json', settings); + } + function setIcon(visible) { + updateSetting('showIcon', visible); + // need to re-layout widgets + WIDGETS["gbridgew"].reload(); + g.clear(); + Bangle.drawWidgets(); + } var mainmenu = { "" : { "title" : "Gadgetbridge" }, "Connected" : { value : NRF.getSecurityStatus().connected?"Yes":"No" }, + "Show Icon" : { + value: settings().showIcon, + format: v => v?"Yes":"No", + onchange: setIcon + }, "Find Phone" : function() { E.showMenu(findPhone); }, "< Back" : back, }; diff --git a/apps/gbridge/widget.js b/apps/gbridge/widget.js index a87b9d1ec..b4c7e1f7b 100644 --- a/apps/gbridge/widget.js +++ b/apps/gbridge/widget.js @@ -1,5 +1,4 @@ (() => { - const state = { music: "stop", @@ -12,147 +11,148 @@ scrollPos: 0 }; + function settings() { + let settings = require('Storage').readJSON("gbridge.json", true) || {}; + if (!("showIcon" in settings)) { + settings.showIcon = true; + } + return settings + } + function gbSend(message) { + Bluetooth.println(""); Bluetooth.println(JSON.stringify(message)); } - function showNotification(size, render, turnOn) { - if (turnOn === undefined) turnOn = true - var oldMode = Bangle.getLCDMode(); - - Bangle.setLCDMode("direct"); - g.setClipRect(0, 240, 239, 319); - g.setColor("#222222"); - g.fillRect(1, 241, 238, 318); - - render(320 - size); - - g.setColor("#ffffff"); - g.fillRect(0, 240, 1, 319); - g.fillRect(238, 240, 239, 319); - g.fillRect(2, 318, 238, 319); - - if (turnOn) Bangle.setLCDPower(1); // light up - Bangle.setLCDMode(oldMode); // clears cliprect - - function anim() { - state.scrollPos -= 2; - if (state.scrollPos < -size) { - state.scrollPos = -size; - } - Bangle.setLCDOffset(state.scrollPos); - if (state.scrollPos > -size) setTimeout(anim, 15); + function prettifyNotificationEvent(event) { + switch (event.src) { + case "ALARMCLOCKRECEIVER": + return { + id: event.id, + title: event.title || "Alarm: "+require('locale').time(new Date(), true), + body: event.body, + // same icon as apps/alarm/app-icon.js + icon: require("heatshrink").decompress(atob("mEwwkGswAhiMRCCAREAo4eHBIQLEAgwYHsIJDiwHB5gACBpIhHCoYZEGA4gFCw4ABGA4HEjgXJ4IXGAwcUB4VEmf//8zogICoJIFAodMBoNDCoIADmgJB4gXIFwXDCwoABngwFC4guB4k/CQXwh4EC+YMCC44iBp4qDC4n/+gNBC41sEIJCEC4v/GAPGC4dhXYRdFC4xhCCYIXCdQRdDC5HzegQXCsxGHC45IDCwQXCUgwXHJAIXGRogXJSIIXcOw4XIPAYXcBwv/mEDBAwXOgtQC65QGC5vzoEAJAx3Nmk/mEABIiPN+dDAQIwFC4zXGFwKRCGAjvMFwQECGAgXI4YuGGAUvAgU8C4/EFwwGCAgdMC4p4EFwobFOwoXDJAIoEAApGBC4xIEABJGHGAapEAAqNBFwwXD4heI+YuBC5BIBVQhdHIw4wD5inFS4IKCCxFmigNCokzCoMzogICoIWIsMRjgPCAA3BiMWC48RBQIXJEgMRFxAJCCw4lEC44IECooOIBAaBJKwhgIAH4ACA==")), + }; + default: + return event; } - anim(); } - - function hideNotification() { - function anim() { - state.scrollPos += 4; - if (state.scrollPos > 0) state.scrollPos = 0; - Bangle.setLCDOffset(state.scrollPos); - if (state.scrollPos < 0) setTimeout(anim, 10); - } - anim(); - } - function handleNotificationEvent(event) { - - // split text up at word boundaries - var txt = event.body.split("\n"); - var MAXCHARS = 38; - for (var i = 0; i < txt.length; i++) { - txt[i] = txt[i].trim(); - var l = txt[i]; - if (l.length > MAXCHARS) { - var p = MAXCHARS; - while (p > MAXCHARS - 8 && !" \t-_".includes(l[p])) - p--; - if (p == MAXCHARS - 8) p = MAXCHARS; - txt[i] = l.substr(0, p); - txt.splice(i + 1, 0, l.substr(p)); - } + if (event.t === "notify") { + require("notify").show(prettifyNotificationEvent(event)); + Bangle.buzz(); + } else { // notify- + require("notify").hide(event); } - - showNotification(80, (y) => { - - // TODO: icon based on src? - var x = 120; - g.setFontAlign(0, 0); - g.setFont("6x8", 1); - g.setColor("#40d040"); - g.drawString(event.src, x, y + 7); - - g.setColor("#ffffff"); - g.setFont("6x8", 2); - if (event.title) - g.drawString(event.title.slice(0,17), x, y + 25); - - g.setFont("6x8", 1); - g.setColor("#ffffff"); - g.setFontAlign(-1, -1); - g.drawString(txt.join("\n"), 10, y + 40); - }); - - Bangle.buzz(); } + function updateMusic(options){ + if (state.music === "play") { + require("notify").show(Object.assign({ + size:40, id:"music", + render:a => { + if (a.h>200) { + // large: + // [icon] + // [ ] + // + // ------------- middle of screen + // + const iconSize = 24*3; // 24x24px, scale 3 + let x = a.x, + y = a.y+a.h/2, // we use coords relative to vertical middle + w=a.w,h=a.h; + // try to fit musicInfo property into width + const fitFont = (prop,max) => { + if (!(prop in state.musicInfo)) return max; + let size = Math.floor(w/(state.musicInfo[prop].length*6)); + if (size<1) {size=1} + if (size>max) {size=max} + return size; + } + let aSize = fitFont('artist',3); + // TODO: split long title over multiple lines instead + let tSize = fitFont('track',2); + let bSize = fitFont('album',2); + g.setColor(-1); + // TODO: use a nicer large icon? + g.drawImage( + require("heatshrink").decompress(atob("jEYwILI/EAv/8gP/ARcMgOAASN8h+A/kfwP8n4CD/E/gHgjg/HA=")), + x+(w-iconSize)/2, y-(iconSize+aSize*8)-12, {scale: 3}); + // artist: centered above middle + g.setFontAlign(0, 1).setFont("6x8", aSize).drawString(state.musicInfo.artist, x+w/2, y-4); + // title: left-aligned below middle + g.setFontAlign(-1, -1).setFont("6x8", tSize).drawString(state.musicInfo.track, x, y+4); + // album: centered at bottom + if (state.musicInfo.album) { + // note: using a.y rather than y + g.setFontAlign(0, 1).setFont("6x8", bSize).drawString(state.musicInfo.album, x+w/2, a.y+h); + } + } else { + // regular size: + // [icon] <artist> + // [ ] <title> + const size=40, iconSize = 24; + let x = a.x, + y = a.y+(a.h-size)/2; // center vertically in available area + g.setColor(-1); + g.drawImage( + require("heatshrink").decompress(atob("jEYwILI/EAv/8gP/ARcMgOAASN8h+A/kfwP8n4CD/E/gHgjg/HA=")), + x+8, y+8); + g.setFontAlign(-1, -1); + x += iconSize+16; + g.setFont("4x6", 2).drawString(state.musicInfo.artist, x, y+8); + g.setFont("6x8", 1).drawString(state.musicInfo.track, x, y+22); + } + }}, options)); + } + + if (state.music === "pause") { + require("notify").hide("music"); + } + } function handleMusicStateUpdate(event) { - const changed = state.music === event.state - state.music = event.state - - if (state.music == "play") { - showNotification(40, (y) => { - g.setColor("#ffffff"); - g.drawImage(require("heatshrink").decompress(atob("jEYwILI/EAv/8gP/ARcMgOAASN8h+A/kfwP8n4CD/E/gHgjg/HA=")), 8, y + 8); - - g.setFontAlign(-1, -1); - var x = 40; - g.setFont("4x6", 2); - g.setColor("#ffffff"); - g.drawString(state.musicInfo.artist, x, y + 8); - - g.setFont("6x8", 1); - g.setColor("#ffffff"); - g.drawString(state.musicInfo.track, x, y + 22); - }, changed); - } - - if (state.music == "pause") { - hideNotification(); + if (state.music !== event.state) { + state.music = event.state + updateMusic({on: true}); } } + function handleMusicInfoUpdate(event) { + state.musicInfo = event; + updateMusic({on: false}); + } function handleCallEvent(event) { - - if (event.cmd == "accept") { - showNotification(40, (y) => { - g.setColor("#ffffff"); - g.drawImage(require("heatshrink").decompress(atob("jEYwIMJj4CCwACJh4CCCIMOAQMGAQMHAQMDAQMBCIMB4PwgHz/EAn4CBj4CBg4CBgACCAAw=")), 8, y + 8); - - g.setFontAlign(-1, -1); - var x = 40; - g.setFont("4x6", 2); - g.setColor("#ffffff"); - g.drawString(event.name, x, y + 8); - - g.setFont("6x8", 1); - g.setColor("#ffffff"); - g.drawString(event.number, x, y + 22); - }); - + if (event.cmd === "accept") { + require("notify").show({ + size: 55, title: event.name, id: "call", + body: event.number, icon:require("heatshrink").decompress(atob("jEYwIMJj4CCwACJh4CCCIMOAQMGAQMHAQMDAQMBCIMB4PwgHz/EAn4CBj4CBg4CBgACCAAw="))}); Bangle.buzz(); } } + function handleFindEvent(event) { + if (state.find) { + clearInterval(state.find); + delete state.find; + } + if (event.n) + state.find = setInterval(_=>{ + Bangle.buzz(); + setTimeout(_=>Bangle.beep(), 1000); + },2000); + } + var _GB = global.GB; global.GB = (event) => { switch (event.t) { case "notify": + case "notify-": handleNotificationEvent(event); break; case "musicinfo": - state.musicInfo = event; + handleMusicInfoUpdate(event); break; case "musicstate": handleMusicStateUpdate(event); @@ -160,19 +160,15 @@ case "call": handleCallEvent(event); break; + case "find": + handleFindEvent(event); + break; } if(_GB)setTimeout(_GB,0,event); }; - // Touch control - Bangle.on("touch", () => { - if (state.scrollPos) { - hideNotification(); - } - }); - Bangle.on("swipe", (dir) => { - if (state.music == "play") { + if (state.music === "play") { const command = dir > 0 ? "next" : "previous" gbSend({ t: "music", n: command }); } @@ -191,10 +187,28 @@ g.flip(); // turns screen on } - NRF.on("connect", changedConnectionState); - NRF.on("disconnect", changedConnectionState); + function reload() { + NRF.removeListener("connect", changedConnectionState); + NRF.removeListener("disconnect", changedConnectionState); + if (settings().showIcon) { + WIDGETS["gbridgew"].width = 24; + WIDGETS["gbridgew"].draw = draw; + NRF.on("connect", changedConnectionState); + NRF.on("disconnect", changedConnectionState); + } else { + WIDGETS["gbridgew"].width = 0; + WIDGETS["gbridgew"].draw = ()=>{}; + } + } - WIDGETS["gbridgew"] = { area: "tl", width: 24, draw: draw }; + WIDGETS["gbridgew"] = {area: "tl", width: 24, draw: draw, reload: reload}; + reload(); - gbSend({ t: "status", bat: E.getBattery() }); + function sendBattery() { + gbSend({ t: "status", bat: E.getBattery() }); + } + + NRF.on("connect", () => setTimeout(sendBattery, 2000)); + setInterval(sendBattery, 10*60*1000); + sendBattery(); })(); diff --git a/apps/gesture/ChangeLog b/apps/gesture/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/gesture/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/getup/ChangeLog b/apps/getup/ChangeLog new file mode 100644 index 000000000..9297fc6c7 --- /dev/null +++ b/apps/getup/ChangeLog @@ -0,0 +1 @@ +0.01: First Version \ No newline at end of file diff --git a/apps/getup/README.md b/apps/getup/README.md new file mode 100644 index 000000000..b92bedb7c --- /dev/null +++ b/apps/getup/README.md @@ -0,0 +1,7 @@ +# Get Up + +Reminds you to getup every x minutes (default: 20). + +Sitting to long is dangerous! + +Sit and move time configurable in settings. diff --git a/apps/getup/app-icon.js b/apps/getup/app-icon.js new file mode 100644 index 000000000..09010684e --- /dev/null +++ b/apps/getup/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A75wACCJugAAguaGBouFGCwuF53NFxem6PX6/R0wwVF4xgJEwOsFoMrlYDB1gwUL55dCFQIvE65hUL54jBRgQvF6JgaRxQpCF4SUC67BV5ouLF40yGAOBF64ANR4vXwJhCR6oABq4ACF5TvDAAOsL4LvS4wuGGBi6DGIYuSAAQvGMJiSC6JdSGAovPGAQAFXSQvDrgrBqwvMGAzqTF4d/F4owLADKQGmQv/F7eAF4UySQQwn0ZcCq0ylkySFYyDMEgvDvQwFAAYvk0aLBqy/CAAaUhSAi+BX4QzCAwJkgF4eAX4gzDSsIvDeIzFlGAhhEF9QAHBwIwvF8IwSF7oxMF8gALSEQwRF/4v/YH4v/GD4usAH4A/AH4ARA=")) diff --git a/apps/getup/app.js b/apps/getup/app.js new file mode 100644 index 000000000..3a22aa410 --- /dev/null +++ b/apps/getup/app.js @@ -0,0 +1,45 @@ +//init settings +const storage = require("Storage"); +const SETTINGS_FILE = 'getup.settings.json'; + +function setting(key) { + const DEFAULTS = { + 'sitTime' : 20, + 'moveTime' : 1 + } + if (!settings) { + loadSettings(); + } + return (key in settings) ? settings[key] : DEFAULTS[key]; +} + +let settings; + +function loadSettings() { + settings = storage.readJSON(SETTINGS_FILE, 1) || {}; +} + +//vibrate, draw move message and start timer for sitting message +function remind() { + Bangle.buzz(1000,1); + g.clear(); + g.setFont("8x12",4); + g.setColor(0x03E0); + g.drawString("MOVE!", g.getWidth()/2, g.getHeight()/2); + setTimeout(print_message,setting("moveTime") * 60000); +} +//draw sitting message and start timer for reminder +function print_message(){ + g.clear(); + g.setFont("8x12",2); + g.setColor(0xF800); + g.drawString("sitting is dangerous!", g.getWidth()/2, g.getHeight()/2); + setTimeout(remind,setting("sitTime") * 60000); +} + +//init graphics +require("Font8x12").add(Graphics); +g.setFontAlign(0,0); +g.flip(); + +print_message(); diff --git a/apps/getup/app.png b/apps/getup/app.png new file mode 100644 index 000000000..fec421183 Binary files /dev/null and b/apps/getup/app.png differ diff --git a/apps/getup/settings.js b/apps/getup/settings.js new file mode 100644 index 000000000..f34262f2a --- /dev/null +++ b/apps/getup/settings.js @@ -0,0 +1,48 @@ +// This file should contain exactly one function, which shows the app's settings +/** + * @param {function} back Use back() to return to settings menu + */ +(function(back) { + const SETTINGS_FILE = 'getup.settings.json'; + + // initialize with default settings... + let s = { + 'sitTime' : 20, + 'moveTime' : 1 + }; + // ...and overwrite them with any saved values + // This way saved values are preserved if a new version adds more settings + const storage = require('Storage'); + const saved = storage.readJSON(SETTINGS_FILE, 1) || {}; + for (const key in saved) { + s[key] = saved[key]; + } + + // creates a function to safe a specific setting, e.g. save('color')(1) + function save(key) { + return function (value) { + s[key] = value; + storage.write(SETTINGS_FILE, s); + }; + } + + const menu = { + '': { 'title': 'Get Up' }, + '< Back': back, + 'Sit time (min)': { + value: s.sitTime, + min: 0, + max: 10000, + step: 1, + onchange: save('sitTime'), + }, + 'Move time (min)': { + value: s.moveTime, + min: 0, + max: 5000, + step: 1, + onchange: save('moveTime'), + }, + }; + E.showMenu(menu); +}); diff --git a/apps/gpsautotime/ChangeLog b/apps/gpsautotime/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/gpsautotime/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/gpsautotime/widget.js b/apps/gpsautotime/widget.js new file mode 100644 index 000000000..a1d1b2b08 --- /dev/null +++ b/apps/gpsautotime/widget.js @@ -0,0 +1,33 @@ +(() => { + var lastTimeSet = 0; + + Bangle.on('GPS',function(fix) { + if (fix.fix) { + var curTime = fix.time.getTime()/1000; + setTime(curTime); + lastTimeSet = curTime; + + WIDGETS["gpsAutoTime"].draw(WIDGETS["gpsAutoTime"]); + } + }); + + // add your widget + WIDGETS["gpsAutoTime"]={ + area:"tl", // tl (top left), tr (top right), bl (bottom left), br (bottom right) + width: 28, // width of the widget + draw: function() { + g.reset(); // reset the graphics context to defaults (color/font/etc) + g.setFont("6x8"); + if ((getTime() - lastTimeSet) <= 60) { + // time is uptodate + g.setColor('#00ff00'); // green + } + g.drawString("auto", this.x, this.y); + g.drawString("time", this.x, this.y+10); + } + }; + + setInterval(function() { + WIDGETS["gpsAutoTime"].draw(WIDGETS["gpsAutoTime"]); + }, 1*60000); // update every minute +})() diff --git a/apps/gpsautotime/widget.png b/apps/gpsautotime/widget.png new file mode 100644 index 000000000..6f6e23f2f Binary files /dev/null and b/apps/gpsautotime/widget.png differ diff --git a/apps/gpsnav/ChangeLog b/apps/gpsnav/ChangeLog new file mode 100644 index 000000000..ee8b61d7b --- /dev/null +++ b/apps/gpsnav/ChangeLog @@ -0,0 +1,4 @@ +0.01: New App! +0.02: Add SCREENACCESS interface +0.03: Add Waypoint Editor +0.04: Fix great circle formula diff --git a/apps/gpsnav/README.md b/apps/gpsnav/README.md new file mode 100644 index 000000000..af239b233 --- /dev/null +++ b/apps/gpsnav/README.md @@ -0,0 +1,62 @@ +## gpsnav - navigate to waypoints + +The app is aimed at small boat navigation although it can also be used to mark the location of your car, bicycle etc and then get directions back to it. Please note that it would be foolish in the extreme to rely on this as your only boat navigation aid! + +The app displays direction of travel (course), speed, direction to waypoint (bearing) and distance to waypoint. The screen shot below is before the app has got a GPS fix. + +![](first_screen.jpg) + +The large digits are the course and speed. The top of the display is a linear compass which displays the direction of travel when a fix is received and you are moving. The blue text is the name of the current waypoint. NONE means that there is no waypoint set and so bearing and distance will remain at 0. To select a waypoint, press BTN2 (middle) and wait for the blue text to turn white. Then use BTN1 and BTN3 to select a waypoint. The waypoint choice is fixed by pressing BTN2 again. In the screen shot below a waypoint giving the location of Stone Henge has been selected. + +![](waypoint_screen.jpg) + +The display shows that Stone Henge is 108.75Km from the location where I made the screenshot and the direction is 255 degrees - approximately west. The display shows that I am currently moving approximately north - albeit slowly!. The position of the blue circle indicates that I need to turn left to get on course to Stone Henge. When the circle and red triangle line up you are on course and course will equal bearing. + +### Marking Waypoints + +The app lets you mark your current location as follows. There are vacant slots in the waypoint file which can be allocated a location. In the distributed waypoint file these are labelled WP0 to WP4. Select one of these - WP2 is shown below. + +![](select_screen.jpg) + +Bearing and distance are both zero as WP1 has currently no GPS location associated with it. To mark the location, press BTN2. + +![](marked_screen.jpg) + +The app indicates that WP2 is now marked by adding the prefix @ to it's name. The distance should be small as shown in the screen shot as you have just marked your current location. + +### Waypoint JSON file + +When the app is loaded from the app loader, a file named `waypoints.json` is loaded along with the javascript etc. The file has the following contents: + +``` +[ + { + "name":"NONE" + }, + { + "name":"No10", + "lat":51.5032, + "lon":-0.1269 + }, + { + "name":"Stone", + "lat":51.1788, + "lon":-1.8260 + }, + { "name":"WP0" }, + { "name":"WP1" }, + { "name":"WP2" }, + { "name":"WP3" }, + { "name":"WP4" } +] +``` + +The file contains the initial NONE waypoint which is useful if you just want to display course and speed. The next two entries are waypoints to No 10 Downing Street and to Stone Henge - obtained from Google Maps. The last five entries are entries which can be *marked*. + +You add and delete entries using the Web IDE to load and then save the file from and to watch storage. The app itself does not limit the number of entries although it does load the entire file into RAM which will obviously limit this. + +### Waypoint Editor + +Clicking on the download icon of gpsnav in the app loader invokes the waypoint editor. The editor downloads and displays the current `waypoints.json` file. Clicking the `Edit` button beside an entry causes the entry to be deleted from the list and displayed in the edit boxes. It can be restored - by clicking the `Add waypoint` button. A new markable entry is created by using the `Add name` button. The edited `waypoints.json` file is uploaded to the Bangle by clicking the `Upload` button. + +*Please report bugs etc. by raising an issue [here](https://github.com/jeffmer/JeffsBangleAppsDev). * \ No newline at end of file diff --git a/apps/gpsnav/app-icon.js b/apps/gpsnav/app-icon.js new file mode 100644 index 000000000..890981d5a --- /dev/null +++ b/apps/gpsnav/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AFmACysDC9+IC6szC/8AgUgLwYXBPAgLDAA8kC5MyC5cyogXHmYiDURMkDAMzC4JgBmcyoAXMGANCC4YDBkgXMHwVEC4hQDC5kyF4kjJ4QAMOgMjC4eCohGNMARbCC4ODkilLAAQSBCYJ3EmYVLhAWCCgQaCAAUwCpowCFwYADIRAYHC4wZFRQIAGnAhJXgwAFxAYHwC9JFwiQCFhIZISAQwDX5sCoQTCDYUjUpAAFglElAXDmS9JAAtEoUyC4ckkbvMC4QQBC4YeBC5sEB4IXEkgfBJBkEH4QXCCYMkoQXMHwcIC4ZQCUpYMDC4oiBC5YEDC40AkCRNAAIXBCJ4X2URgAJhAXvCyoA/ACoA=")) \ No newline at end of file diff --git a/apps/gpsnav/app.js b/apps/gpsnav/app.js new file mode 100644 index 000000000..3bbc756b7 --- /dev/null +++ b/apps/gpsnav/app.js @@ -0,0 +1,249 @@ +const Yoff = 40; +var pal2color = new Uint16Array([0x0000,0xffff,0x07ff,0xC618],0,2); +var buf = Graphics.createArrayBuffer(240,50,2,{msb:true}); +var candraw = true; + +function flip(b,y) { + g.drawImage({width:240,height:50,bpp:2,buffer:b.buffer, palette:pal2color},0,y); + b.clear(); +} + +var brg=0; +var wpindex=0; +const labels = ["N","NE","E","SE","S","SW","W","NW"]; + +function drawCompass(course) { + if (!candraw) return; + buf.setColor(1); + buf.setFont("Vector",16); + var start = course-90; + if (start<0) start+=360; + buf.fillRect(28,45,212,49); + var xpos = 30; + var frag = 15 - start%15; + if (frag<15) xpos+=frag; else frag = 0; + for (var i=frag;i<=180-frag;i+=15){ + var res = start + i; + if (res%90==0) { + buf.drawString(labels[Math.floor(res/45)%8],xpos-8,0); + buf.fillRect(xpos-2,25,xpos+2,45); + } else if (res%45==0) { + buf.drawString(labels[Math.floor(res/45)%8],xpos-12,0); + buf.fillRect(xpos-2,30,xpos+2,45); + } else if (res%15==0) { + buf.fillRect(xpos,35,xpos+1,45); + } + xpos+=15; + } + if (wpindex!=0) { + var bpos = brg - course; + if (bpos>180) bpos -=360; + if (bpos<-180) bpos +=360; + bpos+=120; + if (bpos<30) bpos = 14; + if (bpos>210) bpos = 226; + buf.setColor(2); + buf.fillCircle(bpos,40,8); + } + flip(buf,Yoff); +} + +//displayed heading +var heading = 0; +function newHeading(m,h){ + var s = Math.abs(m - h); + var delta = 1; + if (s<2) return h; + if (m > h){ + if (s >= 180) { delta = -1; s = 360 - s;} + } else if (m <= h){ + if (s < 180) delta = -1; + else s = 360 -s; + } + delta = delta * (1 + Math.round(s/15)); + heading+=delta; + if (heading<0) heading += 360; + if (heading>360) heading -= 360; + return heading; +} + +var course =0; +var speed = 0; +var satellites = 0; +var wp; +var dist=0; + +function radians(a) { + return a*Math.PI/180; +} + +function degrees(a) { + var d = a*180/Math.PI; + return (d+360)%360; +} + +function bearing(a,b){ + var delta = radians(b.lon-a.lon); + var alat = radians(a.lat); + var blat = radians(b.lat); + var y = Math.sin(delta) * Math.cos(blat); + var x = Math.cos(alat)*Math.sin(blat) - + Math.sin(alat)*Math.cos(blat)*Math.cos(delta); + return Math.round(degrees(Math.atan2(y, x))); +} + +function distance(a,b){ + var dsigma = Math.acos(Math.sin(radians(a.lat))*Math.sin(radians(b.lat))+Math.cos(radians(a.lat))*Math.cos(radians(b.lat))*Math.cos(radians(a.lon-b.lon))); + return Math.round(dsigma*6371000); +} + +var selected = false; + +function drawN(){ + buf.setColor(1); + buf.setFont("6x8",2); + buf.drawString("o",100,0); + buf.setFont("6x8",1); + buf.drawString("kph",220,40); + buf.setFont("Vector",40); + var cs = course.toString(); + cs = course<10?"00"+cs : course<100 ?"0"+cs : cs; + buf.drawString(cs,10,0); + var txt = (speed<10) ? speed.toFixed(1) : Math.round(speed); + buf.drawString(txt,140,4); + flip(buf,Yoff+70); + buf.setColor(1); + buf.setFont("Vector",20); + var bs = brg.toString(); + bs = brg<10?"00"+bs : brg<100 ?"0"+bs : bs; + buf.setColor(3); + buf.drawString("Brg: ",0,0); + buf.drawString("Dist: ",0,30); + buf.setColor(selected?1:2); + buf.drawString(wp.name,140,0); + buf.setColor(1); + buf.drawString(bs,60,0); + if (dist<1000) + buf.drawString(dist.toString()+"m",60,30); + else + buf.drawString((dist/1000).toFixed(2)+"Km",60,30); + flip(buf,Yoff+130); + g.setFont("6x8",1); + g.setColor(0,0,0); + g.fillRect(10,230,60,239); + g.setColor(1,1,1); + g.drawString("Sats " + satellites.toString(),10,230); +} + +var savedfix; + +function onGPS(fix) { + savedfix = fix; + if (fix!==undefined){ + course = isNaN(fix.course) ? course : Math.round(fix.course); + speed = isNaN(fix.speed) ? speed : fix.speed; + satellites = fix.satellites; + } + if (candraw) { + if (fix!==undefined && fix.fix==1){ + dist = distance(fix,wp); + if (isNaN(dist)) dist = 0; + brg = bearing(fix,wp); + if (isNaN(brg)) brg = 0; + } + drawN(); + } +} + +var intervalRef; + +function stopdraw() { + candraw=false; + if(intervalRef) {clearInterval(intervalRef);} +} + +function startTimers() { + candraw=true; + intervalRefSec = setInterval(function() { + newHeading(course,heading); + if (course!=heading) drawCompass(heading); + },200); +} + +function drawAll(){ + g.setColor(1,0.5,0.5); + g.fillPoly([120,Yoff+50,110,Yoff+70,130,Yoff+70]); + g.setColor(1,1,1); + drawN(); + drawCompass(heading); +} + +function startdraw(){ + g.clear(); + Bangle.drawWidgets(); + startTimers(); + drawAll(); +} + +function setButtons(){ + setWatch(nextwp.bind(null,-1), BTN1, {repeat:true,edge:"falling"}); + setWatch(doselect, BTN2, {repeat:true,edge:"falling"}); + setWatch(nextwp.bind(null,1), BTN3, {repeat:true,edge:"falling"}); +} + +var SCREENACCESS = { + withApp:true, + request:function(){ + this.withApp=false; + stopdraw(); + clearWatch(); + }, + release:function(){ + this.withApp=true; + startdraw(); + setButtons(); + } +} + +Bangle.on('lcdPower',function(on) { + if (!SCREENACCESS.withApp) return; + if (on) { + startdraw(); + } else { + stopdraw(); + } +}); + +var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"NONE"}]; +wp=waypoints[0]; + +function nextwp(inc){ + if (!selected) return; + wpindex+=inc; + if (wpindex>=waypoints.length) wpindex=0; + if (wpindex<0) wpindex = waypoints.length-1; + wp = waypoints[wpindex]; + drawN(); +} + +function doselect(){ + if (selected && waypoints[wpindex].lat===undefined && savedfix.fix) { + waypoints[wpindex] ={name:"@"+wp.name, lat:savedfix.lat, lon:savedfix.lon}; + wp = waypoints[wpindex]; + require("Storage").writeJSON("waypoints.json", waypoints); + } + selected=!selected; + drawN(); +} + +g.clear(); +Bangle.setLCDBrightness(1); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +// load widgets can turn off GPS +Bangle.setGPSPower(1); +drawAll(); +startTimers(); +Bangle.on('GPS', onGPS); +// Toggle selected +setButtons(); diff --git a/apps/gpsnav/first_screen.jpg b/apps/gpsnav/first_screen.jpg new file mode 100644 index 000000000..34fbe1b50 Binary files /dev/null and b/apps/gpsnav/first_screen.jpg differ diff --git a/apps/gpsnav/gpsnav.jpg b/apps/gpsnav/gpsnav.jpg new file mode 100644 index 000000000..975fe3903 Binary files /dev/null and b/apps/gpsnav/gpsnav.jpg differ diff --git a/apps/gpsnav/icon.png b/apps/gpsnav/icon.png new file mode 100644 index 000000000..f899683d1 Binary files /dev/null and b/apps/gpsnav/icon.png differ diff --git a/apps/gpsnav/marked_screen.jpg b/apps/gpsnav/marked_screen.jpg new file mode 100644 index 000000000..accd3b15f Binary files /dev/null and b/apps/gpsnav/marked_screen.jpg differ diff --git a/apps/gpsnav/select_screen.jpg b/apps/gpsnav/select_screen.jpg new file mode 100644 index 000000000..8e42411b0 Binary files /dev/null and b/apps/gpsnav/select_screen.jpg differ diff --git a/apps/gpsnav/waypoint_screen.jpg b/apps/gpsnav/waypoint_screen.jpg new file mode 100644 index 000000000..f4c946ee6 Binary files /dev/null and b/apps/gpsnav/waypoint_screen.jpg differ diff --git a/apps/gpsnav/waypoints.html b/apps/gpsnav/waypoints.html new file mode 100644 index 000000000..d02260732 --- /dev/null +++ b/apps/gpsnav/waypoints.html @@ -0,0 +1,170 @@ +<html> + <head> + <link rel="stylesheet" href="../../css/spectre.min.css"> + <link rel="stylesheet" href="../../css/spectre-icons.min.css"> + </head> + <body> + + <h4>List of waypoints</h4> + <table class="table"> + <thead> + <tr> + <th>Name</th> + <th>Lat.</th> + <th>Long.</th> + <th>Actions</th> + </tr> + </thead> + <tbody id="waypoints"> + + </tbody> + </table> + <br> + <h4>Add a new waypoint</h4> + <form id="add_waypoint_form"> + <div class="columns"> + <div class="column col-3 col-xs-8"> + <input class="form-input input-sm" type="text" id="add_waypoint_name" placeholder="Name"> + </div> + <div class="column col-3 col-xs-8"> + <input class="form-input input-sm" value="0.0000" type="number" step="any" id="add_latitude" placeholder="Lat"> + </div> + <div class="column col-3 col-xs-8"> + <input class="form-input input-sm" value="0.0000" type="number" step="any" id="add_longtitude" placeholder="Long"> + </div> + </div> + <div class="columns"> + <div class="column col-3 col-xs-8"> + <button id="add_name_button" class="btn btn-primary btn-sm">Add Name Only</button> + </div> + <div class="column col-3 col-xs-8"> + <button id="add_waypoint_button" class="btn btn-primary btn-sm">Add Waypoint</button> + </div> + </div> + </form> + <br> + <button id="Download" class="btn btn-error">Reload</button> <button id="Upload" class="btn btn-primary">Upload</button> + + <script src="../../core/lib/interface.js"></script> + + <script> + + var waypoints = [] + + var $name = document.getElementById('add_waypoint_name') + var $form = document.getElementById('add_waypoint_form') + var $button = document.getElementById('add_waypoint_button') + var $name_button = document.getElementById('add_name_button') + var $latitude = document.getElementById('add_latitude') + var $longtitude = document.getElementById('add_longtitude') + var $list = document.getElementById('waypoints') + + function compare(a, b){ + var x = a.name.toLowerCase(); + var y = b.name.toLowerCase(); + if (x=="none") {return -1}; + if (y=="none") {return 1}; + if (x < y) {return -1;} + if (x > y) {return 1;} + return 0; + } + + $button.addEventListener('click', event => { + event.preventDefault() + var name = $name.value.trim() + if(!name) return; + var lat = parseFloat($latitude.value).toPrecision(5); + var lon = parseFloat($longtitude.value).toPrecision(5); + + waypoints.push({ + name, lat,lon, + }); + + waypoints.sort(compare); + + renderWaypoints() + $name.value = '' + $latitude.value = (0).toPrecision(5); + $longtitude.value = (0).toPrecision(5); + }); + + $name_button.addEventListener('click', event => { + event.preventDefault() + var name = $name.value.trim() + if(!name) return; + + waypoints.push({ + name + }); + waypoints.sort(compare); + + renderWaypoints() + $name.value = '' + $latitude.value = 0.0000 + $longtitude.value = 0.0000 + }); + + + function removeWaypoint(index){ + $name.value = waypoints[index].name + $latitude.value = waypoints[index].lat + $longtitude.value = waypoints[index].lon + waypoints = waypoints.filter((p,i) => i!==index) + renderWaypoints() + } + + function renderWaypoints(){ + $list.innerHTML = '' + waypoints.forEach((waypoint,index) => { + var $waypoint = document.createElement('tr') + if (index==0){ + $waypoint.innerHTML = `<td>${waypoint.name}</td>` + } else if(waypoint.lat==undefined){ + $waypoint.innerHTML = `<td>${waypoint.name}</td><td>------</td><td>-----</td><td><button class="btn btn-action btn-primary" onclick="removeWaypoint(${index})"><i class="icon icon-edit"></i></button></td>` + } else { + $waypoint.innerHTML = `<td>${waypoint.name}</td><td>${waypoint.lat}</td><td>${waypoint.lon}</td><td><button class="btn btn-action btn-primary" onclick="removeWaypoint(${index})"><i class="icon icon-edit"></i></button></td>` + } + $list.appendChild($waypoint) + }) + $name.focus() + } + + function downloadJSONfile(fileid, callback) { + Puck.write(`\x10(function() { + var pts = require("Storage").readJSON("${fileid}")||[{name:"NONE"}]; + Bluetooth.print(JSON.stringify(pts)); + })()\n`,contents=>{ + var storedpts = JSON.parse(contents); + callback(storedpts); + }); + } + + function uploadFile(fileid, contents) { + Puck.write(`\x10(function() { + require("Storage").write("${fileid}",'${contents}'); + Bluetooth.print("OK"); + })()\n`,ret=>{ + console.log("uploadFile",ret); + }); + } + + function gotStored(pts){ + waypoints = pts; + renderWaypoints(); + } + + function onInit() { + downloadJSONfile("waypoints.json", gotStored); + } + + document.getElementById("Download").addEventListener("click", function() { + downloadJSONfile("waypoints.json", gotStored); + }); + + document.getElementById("Upload").addEventListener("click", function() { + var data = JSON.stringify(waypoints); + uploadFile("waypoints.json",data); + }); + </script> + </body> +</html> diff --git a/apps/gpsnav/waypoints.json b/apps/gpsnav/waypoints.json new file mode 100644 index 000000000..98a670c0d --- /dev/null +++ b/apps/gpsnav/waypoints.json @@ -0,0 +1,20 @@ +[ + { + "name":"NONE" + }, + { + "name":"No10", + "lat":51.5032, + "lon":-0.1269 + }, + { + "name":"Stone", + "lat":51.1788, + "lon":-1.8260 + }, + { "name":"WP0" }, + { "name":"WP1" }, + { "name":"WP2" }, + { "name":"WP3" }, + { "name":"WP4" } +] \ No newline at end of file diff --git a/apps/gpspoilog/ChangeLog b/apps/gpspoilog/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/gpspoilog/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/gpspoilog/app-icon.js b/apps/gpspoilog/app-icon.js new file mode 100644 index 000000000..89f8d1bd7 --- /dev/null +++ b/apps/gpspoilog/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AEeGAAwttGMotLGMItPGLwuTGDQuVGDIfHq9RAAgvfDw+AFwtRq4weFZYAIwAvYJIguPSowvavl8F8qpFF6wwSF44AFvl9vo3GF8l80+t1unGAovkvovDvovrAAQvqR4IACR9TviGAovHABIuXF/4vgGAmAFx+AFzDxGACYvVGDAuWF+AwWFzAvwGCguaGCYucF+AwQFzwvwGBwugGBouiF+AwKF0gwJF0wwHF1AvwGAguqGAYusAH4A/AFI=")) diff --git a/apps/gpspoilog/app.js b/apps/gpspoilog/app.js new file mode 100644 index 000000000..2da0c0e7e --- /dev/null +++ b/apps/gpspoilog/app.js @@ -0,0 +1,67 @@ +var menuItems = { + "":{title:"GPS POI Log"}, + " ":{value:"No Fix"}, + "Tree" : ()=>addItem("Tree"), + "Gate" : ()=>addItem("Gate"), + "Flower" : ()=>addItem("Flower"), + "Plant" : ()=>addItem("Plant"), + "Bus Stop" : ()=>addItem("Bus Stop"), + "Pub" : ()=>addItem("Pub") +}; + +var menu = E.showMenu(menuItems); +var gps = { fix : 0}; +var gpsCount = 0; +var file = require("Storage").open("gpspoilog.csv","a"); + +function setStatus(msg) { + menuItems[" "].value = msg; + menu.draw(); +} + +Bangle.on('GPS',function(g) { + gps = g; + gpsCount++; + var msg; + if (g.fix) { + msg = g.satellites + " Satellites"; + } else { + msg = "No Fix"; + } + setStatus(msg+" "+"-\\|/"[gpsCount&3]); +}); + + +function addItem(name) { + if (!gps.fix) { + setStatus("Ignored - no fix"); + return; // don't do anything as no fix + } + // The fields we want to put in out CSV file + var csv = [ + 0|getTime(), // Time to the nearest second + gps.lat, + gps.lon, + gps.alt, + name + ]; + // Write data here + file.write(csv.join(",")+"\n"); + setStatus("Written"); +} + + +Bangle.loadWidgets(); +Bangle.drawWidgets(); +Bangle.setGPSPower(1); + + + +function getData(callback) { + var f = require("Storage").open("gpspoilog.csv","r"); + var l = f.readLine(); + while (l!==undefined) { + callback(l); + l = f.readLine(); + } +} diff --git a/apps/gpspoilog/app.png b/apps/gpspoilog/app.png new file mode 100644 index 000000000..b323bb283 Binary files /dev/null and b/apps/gpspoilog/app.png differ diff --git a/apps/gpspoilog/interface.html b/apps/gpspoilog/interface.html new file mode 100644 index 000000000..e9ca02464 --- /dev/null +++ b/apps/gpspoilog/interface.html @@ -0,0 +1,69 @@ +<html> + <head> + <link rel="stylesheet" href="../../css/spectre.min.css"> + </head> + <body> + <div id="data"></div> + <button class="btn btn-default" id="btnSave">Save</button> + <button class="btn btn-default" id="btnDelete">Delete</button> + + <script src="../../core/lib/interface.js"></script> + <script> +var dataElement = document.getElementById("data"); +var csvData = ""; + +function getData() { + // show loading window + Util.showModal("Loading..."); + // get the data + dataElement.innerHTML = ""; + Util.readStorageFile(`gpspoilog.csv`,data=>{ + csvData = data.trim(); + // remove window + Util.hideModal(); + // If no data, report it and exit + if (data.length==0) { + dataElement.innerHTML = "<b>No data found</b>"; + return; + } + // Otherwise parse the data and output it as a table + dataElement.innerHTML = `<table> + <tr> + <th>Time</th> + <th>Lat</th> + <th>Lon</th> + <th>Alt</th> + <th>Type</th> + </tr>`+data.trim().split("\n").map(l=>{ + l = l.split(","); + return `<tr> + <td>${(new Date(l[0]*1000)).toLocaleString()}</td> + <td>${l[1]}</td> + <td>${l[2]}</td> + <td>${l[3]}</td> + <td>${l[4]}</td> + </tr>` + }).join("\n")+"</table>"; + }); +} + +// You can call a utility function to save the data +document.getElementById("btnSave").addEventListener("click", function() { + Util.saveCSV("gpsdata", csvData); +}); +// Or you can also delete the file +document.getElementById("btnDelete").addEventListener("click", function() { + Util.showModal("Deleting..."); + Util.eraseStorageFile("gpspoilog.csv", function() { + Util.hideModal(); + getData(); + }); +}); +// Called when app starts +function onInit() { + getData(); +} + + </script> + </body> +</html> diff --git a/apps/gpsrec/ChangeLog b/apps/gpsrec/ChangeLog index 8f1c575a1..b002e9914 100644 --- a/apps/gpsrec/ChangeLog +++ b/apps/gpsrec/ChangeLog @@ -5,3 +5,11 @@ 0.05: Tweaks for variable size widget system 0.06: Ensure widget update itself (fix #118) and change to using icons 0.07: Added @jeffmer's awesome track viewer +0.08: Don't overwrite existing settings on app update + Clean up recorded tracks on app removal +0.09: Change default GPS period to 10 (1 is overkill for most uses and makes things slow) + Added RAM keyword to functions & other tweaks to speed up rendering + Going 'back' from track view now doesn't load again +0.10: Can now graph altitude & speed +0.11: Ensure we don't turn GPS off if it was previously on (eg from another app/widget) +0.12: Add option to plot on top of OpenStreetMap tiles (when they are installed on the watch) diff --git a/apps/gpsrec/app-settings.json b/apps/gpsrec/app-settings.json index 7e1c8ee72..4265e46ec 100644 --- a/apps/gpsrec/app-settings.json +++ b/apps/gpsrec/app-settings.json @@ -1,5 +1,5 @@ { "recording":false, "file":0, - "period":1 + "period":10 } diff --git a/apps/gpsrec/app.js b/apps/gpsrec/app.js index 63f3840ff..7b01786a5 100644 --- a/apps/gpsrec/app.js +++ b/apps/gpsrec/app.js @@ -2,6 +2,7 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); var settings = require("Storage").readJSON("gpsrec.json",1)||{}; +var qOpenStMap = (require("Storage").list("openstmap.json")>0); function getFN(n) { return ".gpsrc"+n.toString(36); @@ -60,7 +61,7 @@ function viewTracks() { for (var n=0;n<36;n++) { var f = require("Storage").open(getFN(n),"r"); if (f.readLine()!==undefined) { - menu["Track "+n] = viewTrack.bind(null,n); + menu["Track "+n] = viewTrack.bind(null,n,false); found = true; } } @@ -71,6 +72,7 @@ function viewTracks() { } function getTrackInfo(fn) { + "ram" var filename = getFN(fn); var minLat = 90; var maxLat = -90; @@ -88,8 +90,8 @@ function getTrackInfo(fn) { // pushed this loop together to try and bump loading speed a little while(l!==undefined) { ++nl;c=l.split(","); - n = parseFloat(c[1]);if(n>maxLat)maxLat=n;if(n<minLat)minLat=n; - n = parseFloat(c[2]);if(n>maxLong)maxLong=n;if(n<minLong)minLong=n; + n = +c[1];if(n>maxLat)maxLat=n;if(n<minLat)minLat=n; + n = +c[2];if(n>maxLong)maxLong=n;if(n<minLong)minLong=n; l = f.readLine(f); } if (c) duration = parseInt(c[0]) - starttime; @@ -116,9 +118,11 @@ function asTime(v){ return ""+mins.toString()+"m "+secs.toString()+"s"; } -function viewTrack(n) { - E.showMessage("Loading...","GPS Track "+n); - var info = getTrackInfo(n); +function viewTrack(n, info) { + if (!info) { + E.showMessage("Loading...","GPS Track "+n); + info = getTrackInfo(n); + } const menu = { '': { 'title': 'GPS Track '+n } }; @@ -126,9 +130,21 @@ function viewTrack(n) { menu[info.time.toISOString().substr(0,16).replace("T"," ")] = function(){}; menu["Duration"] = { value : asTime(info.duration)}; menu["Records"] = { value : ""+info.records }; - menu['Plot'] = function() { + menu['Plot Map'] = function() { + info.qOSTM = false; plotTrack(info); }; + if (qOpenStMap) + menu['Plot OpenStMap'] = function() { + info.qOSTM = true; + plotTrack(info); + } + menu['Plot Alt.'] = function() { + plotGraph(info, "altitude"); + }; + menu['Plot Speed'] = function() { + plotGraph(info, "speed"); + }; menu['Erase'] = function() { E.showPrompt("Delete Track?").then(function(v) { if (v) { @@ -138,21 +154,35 @@ function viewTrack(n) { f.erase(); viewTracks(); } else - viewTrack(n); + viewTrack(n, info); }); }; menu['< Back'] = viewTracks; return E.showMenu(menu); } -function plotTrack(info) { - function xcoord(long){ - return 30 + Math.round((long-info.minLong)*info.lfactor*info.scale); +function drawopenstmap(lat, lon, map) { + var s = require("Storage"); + var cx = g.getWidth()/2; + var cy = g.getHeight()/2; + var p = Bangle.project({lat:lat,lon:lon}); + var ix = (p.x-map.center.x)*4096/map.scale + (map.imgx/2) - cx; + var iy = (map.center.y-p.y)*4096/map.scale + (map.imgy/2) - cy; + var tx = 0|(ix/map.tilesize); + var ty = 0|(iy/map.tilesize); + var ox = (tx*map.tilesize)-ix; + var oy = (ty*map.tilesize)-iy; + for (var x=ox,ttx=tx;x<g.getWidth();x+=map.tilesize,ttx++) { + for (var y=oy,tty=ty;y<g.getHeight();y+=map.tilesize,tty++) { + var img = s.read("openstmap-"+ttx+"-"+tty+".img"); + if (img) g.drawImage(img,x,y); + else g.clearRect(x,y,x+map.tilesize-1,y+map.tilesize-1); + } } +} - function ycoord(lat){ - return 210 - Math.round((lat - info.minLat)*info.scale); - } +function plotTrack(info) { + "ram" function radians(a) { return a*Math.PI/180; @@ -164,17 +194,46 @@ function plotTrack(info) { return Math.sqrt(x*x + y*y) * 6371000; } + function getMapXY(mylat, mylon) { + if (info.qOSTM) { + var q = Bangle.project({lat:mylat,lon:mylon}); + var p = Bangle.project({lat:clat,lon:clon}); + var ix = (q.x-p.x)*4096/map.scale + cx; + var iy = cy - (q.y-p.y)*4096/map.scale; + return {x:ix, y:iy}; + } + else { + var ix = 30 + Math.round((long-info.minLong)*info.lfactor*info.scale); + var iy = 210 - Math.round((lat - info.minLat)*info.scale); + return {x:ix, y:iy}; + } + } + E.showMenu(); // remove menu + var s = require("Storage"); + var cx = g.getWidth()/2; + var cy = g.getHeight()/2; g.setColor(1,0.5,0.5); g.setFont("Vector",16); - g.fillRect(9,80,11,120); - g.fillPoly([9,60,19,80,0,80]); - g.setColor(1,1,1); - g.drawString("N",2,40); g.drawString("Track"+info.fn.toString()+" - Loading",10,220); g.setColor(0,0,0); g.fillRect(0,220,239,239); - g.setColor(1,1,1); + if (!info.qOSTM) { + g.setColor(1, 0, 0); + g.fillRect(9,80,11,120); + g.fillPoly([9,60,19,80,0,80]); + g.setColor(1,1,1); + g.drawString("N",2,40); + g.setColor(1,1,1); + } + else { + var map = s.readJSON("openstmap.json"); + map.center = Bangle.project({lat:map.lat,lon:map.lon}); + var clat = (info.minLat+info.maxLat)/2; + var clon = (info.minLong+info.maxLong)/2; + drawopenstmap(clat, clon, map); + g.setColor(0, 0, 0); + } g.drawString(asTime(info.duration),10,220); var f = require("Storage").open(info.filename,"r"); if (f===undefined) return; @@ -182,43 +241,127 @@ function plotTrack(info) { var ox=0; var oy=0; var olat,olong,dist=0; - var first = true; var i=0; + var c = l.split(","); + var lat = +c[1]; + var long = +c[2]; + var mp = getMapXY(lat, long); + g.moveTo(mp.x,mp.y); + g.setColor(0,1,0); + g.fillCircle(mp.x,mp.y,5); + if (info.qOSTM) g.setColor(1,0,0.55); + else g.setColor(1,1,1); + l = f.readLine(f); while(l!==undefined) { - var c = l.split(","); - var lat = parseFloat(c[1]); - var long = parseFloat(c[2]); - var x = xcoord(long); - var y = ycoord(lat); - if (first) { - g.moveTo(x,y); - g.setColor(0,1,0); - g.fillCircle(x,y,5); - g.setColor(1,1,1); - first = false; - } else if (x!=ox || y!=oy) { - g.lineTo(x,y); - } - if (!first) { - var d = distance(olat,olong,lat,long); - if (!isNaN(d)) dist+=d; - } + c = l.split(","); + lat = +c[1]; + long = +c[2]; + mp = getMapXY(lat, long); + g.lineTo(mp.x,mp.y); + if (info.qOSTM) g.fillCircle(mp.x, mp.y, 1); + var d = distance(olat,olong,lat,long); + if (!isNaN(d)) dist+=d; olat = lat; olong = long; - ox = x; - oy = y; + ox = mp.x; + oy = mp.y; l = f.readLine(f); } g.setColor(1,0,0); g.fillCircle(ox,oy,5); - g.setColor(1,1,1); + if (info.qOSTM) g.setColor(0, 0, 0); + else g.setColor(1,1,1); g.drawString(require("locale").distance(dist),120,220); g.setFont("6x8",2); g.setFontAlign(0,0,3); g.drawString("Back",230,200); setWatch(function() { - viewTrack(info.fn); + viewTrack(info.fn, info); }, BTN3); + g.flip(); +} + +function plotGraph(info, style) { + "ram" + E.showMenu(); // remove menu + E.showMessage("Calculating...","GPS Track "+info.fn); + var filename = getFN(info.fn); + var infn = new Float32Array(200); + var infc = new Uint16Array(200); + var title; + var lt = 0; // last time + var tn = 0; // count for each time period + var strt, dur = info.duration; + var f = require("Storage").open(filename,"r"); + if (f===undefined) return; + var l = f.readLine(f); + var nl = 0, c, i; + if (l!==undefined) { + c = l.split(","); + strt = c[0]/1000; + } + if (style=="altitude") { + title = "Altitude (m)"; + while(l!==undefined) { + ++nl;c=l.split(","); + i = Math.round(200*(c[0]/1000 - strt)/dur); + infn[i]+=+c[3]; + infc[i]++; + l = f.readLine(f); + } + } else if (style=="speed") { + title = "Speed (m/s)"; + var p,lp = Bangle.project({lat:c[1],lon:c[2]}); + var t,dx,dy,d,lt = c[0]/1000; + while(l!==undefined) { + ++nl;c=l.split(","); + i = Math.round(200*(c[0]/1000 - strt)/dur); + t = c[0]/1000; + p = Bangle.project({lat:c[1],lon:c[2]}); + dx = p.x-lp.x; + dy = p.y-lp.y; + d = Math.sqrt(dx*dx+dy*dy); + if (t!=lt) { + infn[i]+=d / (t-lt); // speed + infc[i]++; + } + lp = p; + lt = t; + l = f.readLine(f); + } + } else throw new Error("Unknown type"); + var min=100000,max=-100000; + for (var i=0;i<infn.length;i++) { + if (infc[i]>0) infn[i]/=infc[i]; + var n = infn[i]; + if (n>max) max=n; + if (n<min) min=n; + } + // work out a nice grid value + var heightDiff = max-min; + var grid = 1; + while (heightDiff/grid > 8) { + grid*=2; + } + // draw + g.clear(1).setFont("6x8",1); + var r = require("graph").drawLine(g, infn, { + x:4,y:0, + width: g.getWidth()-24, + height: g.getHeight()-8, + axes : true, + gridy : grid, + gridx : 50, + title: title, + xlabel : x=>Math.round(x*dur/(60*infn.length))+" min" // minutes + }); + g.setFont("6x8",2); + g.setFontAlign(0,0,3); + g.drawString("Back",230,200); + setWatch(function() { + viewTrack(info.fn, info); + }, BTN3); + g.flip(); } showMainMenu(); diff --git a/apps/gpsrec/interface.html b/apps/gpsrec/interface.html index bc8dc48e1..837162b74 100644 --- a/apps/gpsrec/interface.html +++ b/apps/gpsrec/interface.html @@ -5,7 +5,7 @@ <body> <div id="tracks"></div> - <script src="../../lib/interface.js"></script> + <script src="../../core/lib/interface.js"></script> <script> var domTracks = document.getElementById("tracks"); diff --git a/apps/gpsrec/widget.js b/apps/gpsrec/widget.js index 2ad0cfc8c..3d110f500 100644 --- a/apps/gpsrec/widget.js +++ b/apps/gpsrec/widget.js @@ -4,6 +4,7 @@ var fixToggle = false; // toggles once for each reading var gpsTrack; // file for GPS track var periodCtr = 0; + var gpsOn = false; // draw your widget function draw() { @@ -11,7 +12,7 @@ g.reset(); g.drawImage(atob("GBgCAAAAAAAAAAQAAAAAAD8AAAAAAP/AAAAAAP/wAAAAAH/8C9AAAB/8L/QAAAfwv/wAAAHS//wAAAAL//gAAAAf/+AAAAAf/4AAAAL//gAAAAD/+DwAAAB/Uf8AAAAfA//AAAACAf/wAAAAAH/0AAAAAB/wAAAAAAfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),this.x,this.y); if (hasFix) { - g.setColor("#FF0000"); + g.setColor("#00FF00"); g.drawImage(fixToggle ? atob("CgoCAAAAA0AAOAAD5AAPwAAAAAAAAAAAAAAAAA==") : atob("CgoCAAABw0AcOAHj5A8PwHwAAvgAB/wABUAAAA=="),this.x,this.y+14); } else { g.setColor("#0000FF"); @@ -41,21 +42,25 @@ // Called by the GPS app to reload settings and decide what to do function reload() { settings = require("Storage").readJSON("gpsrec.json",1)||{}; - settings.period = settings.period||1; + settings.period = settings.period||10; settings.file |= 0; Bangle.removeListener('GPS',onGPS); + var gOn = false; if (settings.recording) { WIDGETS["gpsrec"].width = 24; - Bangle.on('GPS',onGPS); - Bangle.setGPSPower(1); + Bangle.on('GPS', onGPS); var n = settings.file.toString(36); gpsTrack = require("Storage").open(".gpsrc"+n,"a"); + gOn = true; } else { WIDGETS["gpsrec"].width = 0; - Bangle.setGPSPower(0); gpsTrack = undefined; } + if (gOn != gpsOn) { + Bangle.setGPSPower(gOn); + gpsOn = gOn; + } } // add the widget WIDGETS["gpsrec"]={area:"tl",width:24,draw:draw,reload:function() { diff --git a/apps/gpstime/ChangeLog b/apps/gpstime/ChangeLog index e91b36f52..a3bd6351e 100644 --- a/apps/gpstime/ChangeLog +++ b/apps/gpstime/ChangeLog @@ -1 +1,2 @@ 0.03: Fix time output on new firmwares when no GPS time set (fix #104) +0.04: Fix shown UTC time zone sign \ No newline at end of file diff --git a/apps/gpstime/gpstime.js b/apps/gpstime/gpstime.js index 97487ac85..a061d2e23 100644 --- a/apps/gpstime/gpstime.js +++ b/apps/gpstime/gpstime.js @@ -47,7 +47,7 @@ Bangle.on('GPS',function(f) { g.drawString(t[4],120,185); // time if (fix.time) { // timezone - var tz = (new Date()).getTimezoneOffset()/60; + var tz = (new Date()).getTimezoneOffset()/-60; if (tz==0) tz="UTC"; else if (tz>0) tz="UTC+"+tz; else tz="UTC"+tz; diff --git a/apps/grocery/ChangeLog b/apps/grocery/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/grocery/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/grocery/grocery.html b/apps/grocery/grocery.html index 12711375d..14c406d75 100644 --- a/apps/grocery/grocery.html +++ b/apps/grocery/grocery.html @@ -14,7 +14,7 @@ </tr> </thead> <tbody id="products"> - + </tbody> </table> <br><br> @@ -34,8 +34,8 @@ </form> <br><br> <button id="reset" class="btn btn-error">Reset</button> <button id="upload" class="btn btn-primary">Upload</button> - - <script src="../../lib/customize.js"></script> + + <script src="../../core/lib/customize.js"></script> <script> @@ -53,15 +53,15 @@ var $reset = document.getElementById('reset') renderProducts() - + $reset.addEventListener('click', reset) $form.addEventListener('submit', event => { event.preventDefault() - + var name = $name.value.trim() if(!name) return; - + var quantity = parseInt($quantity.value) products.push({ @@ -95,13 +95,13 @@ $list.innerHTML = '' products.forEach((product,index) => { var $product = document.createElement('tr') - + $product.innerHTML = `<td>${product.name}</td><td>${product.quantity}</td><td><button class="btn btn-error" onclick="removeProduct(${index})">remove</button></td>` $list.appendChild($product) }) $name.focus() - + } document.getElementById("upload").addEventListener("click", function() { @@ -152,7 +152,7 @@ E.showMenu(mainMenu); var icon = `require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AQ0QACF1nGAAIxpFoYwqFwwwnRggwGB4eFAggACLzwHCMAeF1WGAgOGw2x2IGCLzYGEF4YpBwotCFwJfWFwo1GSAYtBAIIABRq4vFMhAwBzoAFdzIuKAAOc4IAGGC4qEMZOiF44wXFxovleBYvIGCwmB0WjE4V/AgfG1IvCzujFQOjwoECF6WFwovBDYOFEwN/AgIwCAgOFBwYrBBAQEBzodCF6AAHww1CBpIODAAYvRDAWG2IEBAYYJFBxICCF6Ox1WxAAQfBAYQlCAAIOJAQIvUADQvn1WGR4RfbP4gAFBwgFCF7a5EdwQADF46/cL9wAQF94AGF85bB1TvmF47vdJ4bvFF8qPRFgLv/L7jPCaQq/fYYrvgJgoAGd/7v/F/4v/F5oAdF54weFyAA/AH4A3A="))`; sendCustomizedApp({ storage:[ - {name:"grocery.app.js", content:app}, + {name:"grocery.app.js", url:"app.js", content:app}, {name:"grocery.img", content:icon, evaluate:true}, {name:"grocery"} ] diff --git a/apps/hamloc/ChangeLog b/apps/hamloc/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/hamloc/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/hamloc/README.md b/apps/hamloc/README.md new file mode 100644 index 000000000..6a2a93a44 --- /dev/null +++ b/apps/hamloc/README.md @@ -0,0 +1,18 @@ +# QTH Locator + +Convert your current GPS location to the [Maidenhead](https://en.wikipedia.org/wiki/Maidenhead_Locator_System) locator system used by HAM amateur radio operators. + +## Description + +A Maidenhead locator compresses latitude and longitude into a short string of characters, which is similar in concept to the World Geographic Reference System or GEOREF. This position information is presented in a limited level of precision to limit the number of characters needed for its transmission using voice, Morse code, or any other operating mode. + +The chosen coding uses alternating pairs of letters and digits, like so: + +* BL11bh +## +* support Paul Brewer KI6CQ HamGridSquare.js +* support Chris Veness 2002-2012 LatLon library + +## Requests + +If you have any bug or feature request, please contact [Renaudgweb](https://github.com/renaudgweb/) diff --git a/apps/hamloc/app-icon.js b/apps/hamloc/app-icon.js new file mode 100644 index 000000000..175b492c7 --- /dev/null +++ b/apps/hamloc/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4ACwVeAAM6nQECJsYqDFYItCAgQ0DFrxWE2ZhBxOJA4ICBGwhbbxGtAYOz2etnWt2YwBnQCBGgWtxBjXJQQpBLgQABEQIDBMAgwE2YYBwRcUxOtDwgABGgYvGTQQLCMSRNGEQaODF4SQDHgYwUFIlfAgY2DYQQGDsouCGAQSEGBouEKANl1onEwQvGA4QACA4IwQaIISFFwIwDXwI2ExL2BB4YABJgwwKnQAkRpzYDAAbuBA4oABe4aaDD44uGxCNEQwStEdwgAFR4IHGF4iRBxJeLBwIdCcwgvJxLwFFIRgLBo4dBcwj2CF45xIKIxeLAww4FAAuINIYbKMAteso8FAwovPCQllQQtlF4gLFUYwvDsq/HfIShEDhCQDIgIAFnQHGBBITRnWIXwdfAAYGFSYblBNI5KBsobEDo4GCdxyFDr2tR4+tDQrwNF5YlEnQvJaZIvKr4RIEoovaSAIvyXArbBF6OJR6mCXAgvBDwIlFd5IfBd6tfSQQRGCgeIBJE6DIIAFDoIGGF4OCAgIAEnQHGBBITRnWIF4P+V4ZMCWxBoBRw5PBNI7IGnQuCSAIfE1oSB1oADF4WIXxAvHsoIFH4IvEdIJWEDg4vICRTuJSAwABxAcJF5A5C1ovKRwhgCwSQGF6CpEXxBeGMA59JZIIvGA4hhBLw+JF4xRFSBBNDFIhHFe4VfLxhgCAEguIMAJSB1oABSA4HEB4RwBAgQXHss6LxKRDPQTxBsovIRIdexCOGRpwwIr5gFAwbuEAoheBFyQwFRIrwDLwZuBdwgTBC4IuRYYowGRAq+BAoeCAoRABFyIABD4IsCGAgpFGoguBd4eIFyRiEFoIwCEoKJDRwYqCCAJcUGJICBK4JgDKgOtOIQtce4s6AAI2EBAgteAAizBGgYECwQsiAD4")) diff --git a/apps/hamloc/app.js b/apps/hamloc/app.js new file mode 100644 index 000000000..ac608a5f4 --- /dev/null +++ b/apps/hamloc/app.js @@ -0,0 +1,21 @@ +latLonToGridSquare=function(o,a){var t,e,n,s,l,i,r,h,M,f=-100,g=0,u="ABCDEFGHIJKLMNOPQRSTUVWX",d=u.toLowerCase();function N(o){return"number"==typeof o?o:"string"==typeof o?parseFloat(o):"function"==typeof o?parseFloat(o()):void E.showMessage("can't convert \ninput: "+o)}return"object"==typeof o?2===o.length?(f=N(o[0]),g=N(o[1])):"lat"in o&&"lon"in o?(f=N(o.lat),g=N(o.lon)):"latitude"in o&&"longitude"in o?(f=N(o.latitude),g=N(o.longitude)):E.showMessage("can't convert \nobject "+o):(f=N(o),g=N(a)),isNaN(f)&&E.showMessage("lat is NaN"),isNaN(g)&&E.showMessage("lon is NaN"),90===Math.abs(f)&&E.showMessage("grid invalid \nat N/S"),90<Math.abs(f)&&E.showMessage("invalid lat: \n"+f),180<Math.abs(g)&&E.showMessage("invalid lon: \n"+g),t=f+90,e=g+180,n=u[Math.floor(t/10)],s=u[Math.floor(e/20)],l=""+Math.floor(t%10),i=""+Math.floor(e/2%10),h=60*(t-Math.floor(t)),M=60*(e-2*Math.floor(e/2)),r=d[Math.floor(h/2.5)],s+n+i+l+d[Math.floor(M/5)]+r}; + +Bangle.setGPSPower(1); +var fix; +Bangle.removeAllListeners(); +Bangle.on('GPS',function(f) { + fix=f; + g.clear(); + g.setFontAlign(0,0); + if (!f.fix) { + g.setFont("6x8",3); + g.drawString("Waiting for",120,70); + g.drawString("GPS Fix",120,110); + g.setFont("6x8",2); + g.drawString(f.satellites+" satellites",120,170); + } else { + g.setFont("6x8",5); + var maidenhead = latLonToGridSquare(fix.lat,fix.lon); + g.drawString(maidenhead,120,120); + } +}); diff --git a/apps/hamloc/app.png b/apps/hamloc/app.png new file mode 100644 index 000000000..54dac5882 Binary files /dev/null and b/apps/hamloc/app.png differ diff --git a/apps/heart/ChangeLog b/apps/heart/ChangeLog index 4c4db83bc..70134af27 100644 --- a/apps/heart/ChangeLog +++ b/apps/heart/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! - +0.02: Don't overwrite existing settings on app update + Clean up recordings on app removal diff --git a/apps/heart/interface.html b/apps/heart/interface.html index 4a21d2e27..ce495c805 100644 --- a/apps/heart/interface.html +++ b/apps/heart/interface.html @@ -5,7 +5,7 @@ <body> <div id="records"></div> - <script src="../../lib/interface.js"></script> + <script src="../../core/lib/interface.js"></script> <script> var domRecords = document.getElementById("records"); diff --git a/apps/hidbkbd/ChangeLog b/apps/hidbkbd/ChangeLog new file mode 100644 index 000000000..459bf40b9 --- /dev/null +++ b/apps/hidbkbd/ChangeLog @@ -0,0 +1,2 @@ +0.01: Core functionnality +0.02: Offer to enable HID if disabled. Handle with/without media keys diff --git a/apps/hidbkbd/hid-binary-keyboard.js b/apps/hidbkbd/hid-binary-keyboard.js index fa1017714..4b0401699 100644 --- a/apps/hidbkbd/hid-binary-keyboard.js +++ b/apps/hidbkbd/hid-binary-keyboard.js @@ -45,13 +45,7 @@ const KEY = { 0 : 39 }; -function sendHID(code) { - return new Promise(resolve=>{ - NRF.sendHIDReport([2,0,0,code,0,0,0,0,0], () => { - NRF.sendHIDReport([2,0,0,0,0,0,0,0,0], resolve); - }); - }); -}; +var sendHID; function showChars(x,chars) { var lines = Math.round(Math.sqrt(chars.length)*2); @@ -101,12 +95,26 @@ function startKeyboardHID() { getCharacter().then(ch => { return sendHID(KEY[ch]); }).then(startKeyboardHID); -}; +} -if (!settings.HID) { - E.showMessage('HID disabled'); - setTimeout(load, 1000); -} else { +if (settings.HID=="kb" || settings.HID=="kbmedia") { + if (settings.HID=="kbmedia") { + sendHID = function(code) { + return new Promise(resolve=>{ + NRF.sendHIDReport([2,0,0,code,0,0,0,0,0], () => { + NRF.sendHIDReport([2,0,0,0,0,0,0,0,0], resolve); + }); + }); + }; + } else { + sendHID = function(code) { + return new Promise(resolve=>{ + NRF.sendHIDReport([0,0,code,0,0,0,0,0], () => { + NRF.sendHIDReport([0,0,0,0,0,0,0,0], resolve); + }); + }); + }; + } startKeyboardHID(); setWatch(() => { sendHID(44); // space @@ -114,4 +122,12 @@ if (!settings.HID) { setWatch(() => { sendHID(40); // enter }, BTN3, {repeat:true}); +} else { + E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) { + if (enable) { + settings.HID = "kb"; + require("Storage").write('setting.json', settings); + setTimeout(load, 1000, "hidbkbd.app.js"); + } else setTimeout(load, 1000); + }); } diff --git a/apps/hidcam/ChangeLog b/apps/hidcam/ChangeLog new file mode 100644 index 000000000..480d7d448 --- /dev/null +++ b/apps/hidcam/ChangeLog @@ -0,0 +1,3 @@ +0.01: Core functionnality +0.02: Offer to enable HID if disabled +0.03: Adds Readme and tags to be used by App Loader diff --git a/apps/hidcam/README.md b/apps/hidcam/README.md new file mode 100644 index 000000000..5e8d40817 --- /dev/null +++ b/apps/hidcam/README.md @@ -0,0 +1,18 @@ +# Camera shutter + +Control the camera shutter from your phone using your watch + +## Usage + +1. In settings, enable HID for "Keyboard & Media". +2. Pair your watch to your phone. +3. Load your camera app on your phone. +4. There you go, launch the app on your watch and press button 2 to trigger the shutter ! + +## How does it work ? + +The app uses HID to send the key "Vol +", which is a shortcut for camera trigger on Android and iOS. + +## Creator + +Paul Charlet, using code from HID music app. \ No newline at end of file diff --git a/apps/hidcam/app-icon.js b/apps/hidcam/app-icon.js new file mode 100644 index 000000000..aa9d5e194 --- /dev/null +++ b/apps/hidcam/app-icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("MDCEAzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMxERERERETMzMzMzMzMzMzMzMzMzMzMzMRERERERERMzMzMzMzMzMzMzMzMzMzMzMREREREREREzMzMzMzMzMzMzMzMAAAAzEREREREREREzMzMzMzMzMzMzMzMAAAAxERERERERERETMzMzMzMzMzMzMxERERERERERERERERERERERETMzMzMzMRERERERERERERERERERERERERMzMzMzEREREREREREAAAAAEREREREREREzMzMzEREREREREQAAAAAAABERESIiIREzMzMzEREREREREAAAAAAAAAERESIiIREzMzMzEREREREQAAAKqqqgAAABESIiIREzMzMzEREREREQAAqqqqqqoAABESIiIREzMzMzEREREREAAKqqqqqqqgAAEREREREzMzMzERERERAACqqqqqqqqqAAAREREREzMzMzERERERAAqqqiIiIqqqoAAREREREzMzMzqqqqqgAAqqoiIiIiKqoAAKqqqqozMzMzqqqqqgAKqqIiIiIiKqqgAKqqqqozMzMzqqqqqgAKqqIiqqqiKqqgAKqqqqozMzMzqqqqqgAKqqqqqqqqqqqgAKqqqqozMzMzqqqqqgAKqqqqqqqqqqqgAKqqqqozMzMzqqqqqgAKqqqqqqqqqqqgAKqqqqozMzMzqqqqqgAKqqqqqqqqqqqgAKqqqqozMzMzqqqqqgAAqqqqqqqqqqoAAKqqqqozMzMzqqqqqqAAqqqqqqqqqqoACqqqqqozMzMzqqqqqqAACqqqqqqqqqAACqqqqqozMzMzqqqqqqoAAKqqqqqqqgAAqqqqqqozMzMzqqqqqqoAAAqqqqqqoAAAqqqqqqozMzMzqqqqqqqgAAAKqqqgAAAKqqqqqqozMzMzqqqqqqqqAAAAAAAAAACqqqqqqqozMzMzqqqqqqqqqgAAAAAAAKqqqqqqqqozMzMzqqqqqqqqqqoAAAAAqqqqqqqqqqozMzMzOqqqqqqqqqqqqqqqqqqqqqqqqqMzMzMzM6qqqqqqqqqqqqqqqqqqqqqqqjMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMw==")) diff --git a/apps/hidcam/app.js b/apps/hidcam/app.js new file mode 100644 index 000000000..bb8ddf7e9 --- /dev/null +++ b/apps/hidcam/app.js @@ -0,0 +1,57 @@ +var storage = require('Storage'); + +const settings = storage.readJSON('setting.json',1) || { HID: false }; + +var sendHid, camShot, profile; + +if (settings.HID=="kbmedia") { + profile = 'camShutter'; + sendHid = function (code, cb) { + try { + NRF.sendHIDReport([1,code], () => { + NRF.sendHIDReport([1,0], () => { + if (cb) cb(); + }); + }); + } catch(e) { + print(e); + } + }; + camShot = function (cb) { sendHid(0x80, cb); }; +} else { + E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) { + if (enable) { + settings.HID = "kbmedia"; + require("Storage").write('setting.json', settings); + setTimeout(load, 1000, "hidcam.app.js"); + } else setTimeout(load, 1000); + }); +} +function drawApp() { + g.clear(); + Bangle.loadWidgets(); + Bangle.drawWidgets(); + g.fillCircle(122,127,60); + g.drawImage(storage.read("hidcam.img"),100,105); + const d = g.getWidth() - 18; + + function c(a) { + return { + width: 8, + height: a.length, + bpp: 1, + buffer: (new Uint8Array(a)).buffer + }; + } + g.fillRect(180,130, 240, 124); +} + +if (camShot) { + setWatch(function(e) { + E.showMessage('camShot !'); + setTimeout(drawApp, 1000); + camShot(() => {}); + }, BTN2, { edge:"falling",repeat:true,debounce:50}); + + drawApp(); +} diff --git a/apps/hidcam/app.png b/apps/hidcam/app.png new file mode 100644 index 000000000..3f631a0d8 Binary files /dev/null and b/apps/hidcam/app.png differ diff --git a/apps/hidjoystick/ChangeLog b/apps/hidjoystick/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/hidjoystick/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/hidjoystick/app-icon.js b/apps/hidjoystick/app-icon.js new file mode 100644 index 000000000..21d10dd00 --- /dev/null +++ b/apps/hidjoystick/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AH4ADhvd6AWVAAIYTCwQABC9JGDJCYX/R+7XYgEE7tACycAgczmAX/C/4X/C6kBiMQCyoABDB0N7vdAgIWCAAIXjxAAQCwkIC6OAC/4X/C/4XbgAXRCwgA/AH4ANA")) diff --git a/apps/hidjoystick/app.js b/apps/hidjoystick/app.js new file mode 100644 index 000000000..134814cee --- /dev/null +++ b/apps/hidjoystick/app.js @@ -0,0 +1,74 @@ +var storage = require('Storage'); +const settings = storage.readJSON('setting.json',1) || { HID: false }; + +var sendInProgress = false; // Only send one message at a time, do not flood + +const sendHid = function (x, y, btn1, btn2, btn3, btn4, btn5, cb) { + try { + const buttons = (btn5<<4) | (btn4<<3) | (btn3<<2) | (btn2<<1) | (btn1<<0); + if (!sendInProgress) { + sendInProgress = true; + NRF.sendHIDReport([buttons, x, y], () => { + sendInProgress = false; + if (cb) cb(); + }); + } + } catch(e) { + print(e); + } +}; + +function drawApp() { + g.clear(); + g.setFont("6x8",2); + g.setFontAlign(0,0); + g.drawString("Joystick", 120, 120); + const d = g.getWidth() - 18; + + function c(a) { + return { + width: 8, + height: a.length, + bpp: 1, + buffer: (new Uint8Array(a)).buffer + }; + } + + g.drawImage(c([16,56,124,254,16,16,16,16]),d,40); + g.drawImage(c([16,16,16,16,254,124,56,16]),d,194); + g.drawImage(c([0,8,12,14,255,14,12,8]),d,116); +} + +function update() { + const btn1 = BTN1.read(); + const btn2 = BTN2.read(); + const btn3 = BTN3.read(); + const btn4 = BTN4.read(); + const btn5 = BTN5.read(); + const acc = Bangle.getAccel(); + var x = acc.x*-127; + var y = acc.y*-127; + + // check limits + if (x > 127) x = 127; + else if (x < -127) x = -127; + if (y > 127) y = 127; + else if (y < -127) y = -127; + + sendHid(x & 0xff, y & 0xff, btn1, btn2, btn3, btn4, btn5); +} + +if (settings.HID === "joy") { + drawApp(); + setInterval(update, 100); // 10 Hz +} else { + E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) { + if (enable) { + settings.HID = "joy"; + storage.write('setting.json', settings); + setTimeout(load, 1000, "hidjoystick.app.js"); + } else { + setTimeout(load, 1000); + } + }); +} diff --git a/apps/hidjoystick/app.png b/apps/hidjoystick/app.png new file mode 100644 index 000000000..aca42a818 Binary files /dev/null and b/apps/hidjoystick/app.png differ diff --git a/apps/hidkbd/ChangeLog b/apps/hidkbd/ChangeLog new file mode 100644 index 000000000..459bf40b9 --- /dev/null +++ b/apps/hidkbd/ChangeLog @@ -0,0 +1,2 @@ +0.01: Core functionnality +0.02: Offer to enable HID if disabled. Handle with/without media keys diff --git a/apps/hidkbd/hid-keyboard.js b/apps/hidkbd/hid-keyboard.js index ed406e093..0d489bc0d 100644 --- a/apps/hidkbd/hid-keyboard.js +++ b/apps/hidkbd/hid-keyboard.js @@ -4,27 +4,46 @@ const settings = storage.readJSON('setting.json',1) || { HID: false }; var sendHid, next, prev, toggle, up, down, profile; -if (settings.HID) { +if (settings.HID=="kb" || settings.HID=="kbmedia") { profile = 'Keyboard'; - sendHid = function (code, cb) { - try { - NRF.sendHIDReport([2,0,0,code,0,0,0,0,0], () => { - NRF.sendHIDReport([2,0,0,0,0,0,0,0,0], () => { - if (cb) cb(); + if (settings.HID=="kbmedia") { + sendHid = function (code, cb) { + try { + NRF.sendHIDReport([2,0,0,code,0,0,0,0,0], () => { + NRF.sendHIDReport([2,0,0,0,0,0,0,0,0], () => { + if (cb) cb(); + }); }); - }); - } catch(e) { - print(e); - } - }; + } catch(e) { + print(e); + } + }; + } else { + sendHid = function (code, cb) { + try { + NRF.sendHIDReport([0,0,code,0,0,0,0,0], () => { + NRF.sendHIDReport([0,0,0,0,0,0,0,0], () => { + if (cb) cb(); + }); + }); + } catch(e) { + print(e); + } + }; + } next = function (cb) { sendHid(0x4f, cb); }; prev = function (cb) { sendHid(0x50, cb); }; toggle = function (cb) { sendHid(0x2c, cb); }; up = function (cb) {sendHid(0x52, cb); }; down = function (cb) { sendHid(0x51, cb); }; } else { - E.showMessage('HID disabled'); - setTimeout(load, 1000); + E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) { + if (enable) { + settings.HID = "kb"; + require("Storage").write('setting.json', settings); + setTimeout(load, 1000, "hidkbd.app.js"); + } else setTimeout(load, 1000); + }); } function drawApp() { diff --git a/apps/hidmsic/ChangeLog b/apps/hidmsic/ChangeLog new file mode 100644 index 000000000..9e7c84e5d --- /dev/null +++ b/apps/hidmsic/ChangeLog @@ -0,0 +1,2 @@ +0.01: Core functionnality +0.02: Added BLE HID option for Joystick and bare Keyboard diff --git a/apps/hidmsic/hid-music.js b/apps/hidmsic/hid-music.js index 034bbd231..db81744f3 100644 --- a/apps/hidmsic/hid-music.js +++ b/apps/hidmsic/hid-music.js @@ -4,7 +4,7 @@ const settings = storage.readJSON('setting.json',1) || { HID: false }; var sendHid, next, prev, toggle, up, down, profile; -if (settings.HID) { +if (settings.HID=="kbmedia") { profile = 'Music'; sendHid = function (code, cb) { try { @@ -23,8 +23,13 @@ if (settings.HID) { up = function (cb) {sendHid(0x40, cb); }; down = function (cb) { sendHid(0x80, cb); }; } else { - E.showMessage('HID disabled'); - setTimeout(load, 1000); + E.showPrompt("Enable HID?",{title:"HID disabled"}).then(function(enable) { + if (enable) { + settings.HID = "kbmedia"; + require("Storage").write('setting.json', settings); + setTimeout(load, 1000, "hidmsc.app.js"); + } else setTimeout(load, 1000); + }); } function drawApp() { diff --git a/apps/horsey/horse-race.js b/apps/horsey/horse-race.js index 170ca22f2..bd09e3802 100644 --- a/apps/horsey/horse-race.js +++ b/apps/horsey/horse-race.js @@ -16,13 +16,13 @@ setWatch(x=>{ },BTN1,{repeat:true}); function updateAdvertising() { -try { - NRF.setAdvertising({},{ - manufacturer: 0x0590, - manufacturerData: new Uint8Array([mycounter>>8,mycounter&255]), - interval: 60 - }); -} catch(e){} + try { + NRF.setAdvertising({},{ + manufacturer: 0x0590, + manufacturerData: new Uint8Array([mycounter>>8,mycounter&255]), + interval: 60 + }); + } catch(e){} } function drawPlayers() { @@ -44,7 +44,7 @@ function drawPlayers() { var d = 63 - (offset&63); g.fillRect(0,10,240,12); for (var x=d;x<240;x+=64) - g.fillRect(x,12,x+2,12+20); + g.fillRect(x,12,x+2,12+20); var y = 20; var p = mycounter-offset; g.drawString("You",p-16,y+20); @@ -60,7 +60,7 @@ function drawPlayers() { g.fillRect(0,150,240,152); for (var x=d;x<240;x+=64) - g.fillRect(x,152,x+2,160); + g.fillRect(x,152,x+2,160); g.flip(); } diff --git a/apps/hrings/ChangeLog b/apps/hrings/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/hrings/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/hrm/ChangeLog b/apps/hrm/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/hrm/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/imgclock/122240.png b/apps/imgclock/122240.png new file mode 100644 index 000000000..14b3cf84b Binary files /dev/null and b/apps/imgclock/122240.png differ diff --git a/apps/imgclock/122271.png b/apps/imgclock/122271.png new file mode 100644 index 000000000..cd9b5e45f Binary files /dev/null and b/apps/imgclock/122271.png differ diff --git a/apps/imgclock/ChangeLog b/apps/imgclock/ChangeLog new file mode 100644 index 000000000..20906fb87 --- /dev/null +++ b/apps/imgclock/ChangeLog @@ -0,0 +1,8 @@ +0.01: New App! +0.02: Add configurable color - and 'this is fine.' +0.03: Add {msb:true} so that on new builds, color is correct for 16 bit +0.04: Fix hour alignment for single digits + Scaling for background images <240px wide +0.05: Fix memory/interval leak when LCD turns on +0.06: Support 12 hour time +0.07: Don't cut off wide date formats \ No newline at end of file diff --git a/apps/imgclock/app-icon.js b/apps/imgclock/app-icon.js new file mode 100644 index 000000000..2189484d0 --- /dev/null +++ b/apps/imgclock/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AD1oAaF/4v2nAAUF/4v/F6WJAAQvbw/X69jF54xPF5YuBAAIvnrms64BBAAQGCrgvHnc7r4vYRYXX2QCE6+HF8/W5vN6wvNsqPb6/N5nM5qRCR5QvCsoACF9BeCF4YyKR7ovCYYIvYd6DuCss6nSVBSJSPKSISNCR5a+Cr4vWAAYvDBhAvisYuBsYvPnYvBYAQuIF5gAMF4buDLxovgRxwvcr4uBsqOOF7juELxovDADDuEF9TuERxovfLx4vedwIvtdwKOOAAR1CACIlBr4pBF4RePGDAAFnYvTAAIUCJgQvTRyIwIAAgvPLygyNGhVlF7QyNGgrzCFzQyQsouCF7wyQF8IyNF0YyLF84yHF9QyDF1oA/AH4AeA==")) diff --git a/apps/imgclock/app.js b/apps/imgclock/app.js new file mode 100644 index 000000000..751647a69 --- /dev/null +++ b/apps/imgclock/app.js @@ -0,0 +1,88 @@ +/* +Draws a fullscreen image from flash memory +Saves a small image to flash which is just the area where the clock is +Keeps an offscreen buffer and draws the time to that +*/ +var is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; +var inf = require("Storage").readJSON("imgclock.face.json"); +var img = require("Storage").read("imgclock.face.img"); +var IX = inf.x, IY = inf.y, IBPP = inf.bpp; +var IW = 174, IH = 45, OY = 24; +var bgwidth = img.charCodeAt(0); +var bgoptions; +if (bgwidth<240) + bgoptions = { scale : 240/bgwidth }; + +require("Font7x11Numeric7Seg").add(Graphics); +var cg = Graphics.createArrayBuffer(IW,IH,IBPP,{msb:true}); +var cgimg = {width:IW,height:IH,bpp:IBPP,buffer:cg.buffer}; +var locale = require("locale"); + +// store clock background image in bgimg (a file in flash memory) +var bgimg = require("Storage").read("imgclock.face.bg"); +// if it doesn't exist, make it +function createBgImg() { + cg.drawImage(img,-IX,-IY,bgoptions); + require("Storage").write("imgclock.face.bg", cg.buffer); + bgimg = require("Storage").read("imgclock.face.bg"); +} +if (!bgimg || !bgimg.length) createBgImg(); + +function draw() { + var t = new Date(); + var hours = t.getHours(); + var meridian = ""; + if (is12Hour) { + meridian = (hours < 12) ? "AM" : "PM"; + hours = ((hours + 11) % 12) + 1; + } + // quickly set background image + new Uint8Array(cg.buffer).set(bgimg); + // draw time + cg.setColor(inf.col); + var x = 74 + 32 * inf.align; + cg.setFont("7x11Numeric7Seg",3); + cg.setFontAlign(1,-1); + cg.drawString(hours, x, 0); + x+=2; + if (t.getSeconds() & 1) + cg.fillRect(x, 10, x+2, 10+2).fillRect(x, 20, x+2, 20+2); + x+=6; + cg.setFontAlign(-1,-1); + cg.drawString(("0"+t.getMinutes()).substr(-2), x, 0); + x+=44; + cg.setFont("7x11Numeric7Seg",1); + cg.drawString(("0"+t.getSeconds()).substr(-2), x, 20); + cg.setFont("6x8",1); + cg.drawString(meridian, x+2, 0); + let date = locale.date(t); + if (cg.stringWidth(date) < IW-64) { + cg.setFontAlign(0, -1); + cg.drawString(date,IW/2+32*inf.align,IH-8); + } else { + cg.setFontAlign(inf.align, -1); + cg.drawString(date,IW*(inf.align+1)/2,IH-8); + } + // draw to screen + g.drawImage(cgimg,IX,IY+OY); +} + +// draw background +g.drawImage(img, 0,OY,bgoptions); +// draw clock itself and do it every second +draw(); +var secondInterval = setInterval(draw,1000); +// load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); +// Stop when LCD goes off +Bangle.on('lcdPower',on=>{ + if (secondInterval) clearInterval(secondInterval); + secondInterval = undefined; + if (on) { + secondInterval = setInterval(draw,1000); + draw(); + } +}); +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); diff --git a/apps/imgclock/app.png b/apps/imgclock/app.png new file mode 100644 index 000000000..237f3f82a Binary files /dev/null and b/apps/imgclock/app.png differ diff --git a/apps/imgclock/custom.html b/apps/imgclock/custom.html new file mode 100644 index 000000000..2511f8a54 --- /dev/null +++ b/apps/imgclock/custom.html @@ -0,0 +1,142 @@ +<html> + <head> + <link rel="stylesheet" href="../../css/spectre.min.css"> + </head> + <body> + <div class="container"> + <div class="columns"> + </div> + </div> + + <script src="../../core/lib/customize.js"></script> + <script src="../../core/lib/imageconverter.js"></script> + + <script> + var faces = [ + { img:"122240.png", bpp : 8, x:56, y:20, align: 1, col:"#FFFFFF", name:"Cityscape", attrib:"getwallpapers.com", attribLink:"http://getwallpapers.com/collection/8-bit-wallpaper", description:"" }, + { img:"122271.png", bpp : 8, x:10, y:125, align: -1, col:"#FFFFFF", name:"Sunset", attrib:"getwallpapers.com", attribLink:"http://getwallpapers.com/collection/8-bit-wallpaper", description:"" }, + { img:"thisisfine.png", bpp : 8, x:53, y:5, align: 0, col:"#000000", name:"This is fine.", attrib:"Gunshow #648", attribLink:"https://knowyourmeme.com/memes/this-is-fine", description:"" }, + { img:"explode.png", bpp : 8, x:0, y:145, align: 0, col:"#FFFFFF", name:"Boom.", attrib:"", attribLink:"", description:"" }, + ]; + + document.querySelector(".columns").innerHTML = faces.map((face,facenumber)=>` +<div class="column col-6 col-xs-12"> + <div class="card"> + <div class="card-image"> + <img src="${face.img}" face="${facenumber}" class="img-responsive"> + </div> + <div class="card-header"> + <div class="card-title h5">${face.name}</div> + <div class="card-subtitle text-gray"><a href="${face.attribLink}" target="_blank">${face.attrib}</a></div> + </div> + <div class="card-body">${face.description}</div> + <div class="card-footer"> + <button class="btn btn-primary uploadbutton" face="${facenumber}">Upload</button> + </div> + </div> +</div>`).join("\n")+` +<div class="column col-6 col-xs-12"> + <div class="card"> + <div class="card-image"> + <img id="customimage" src="" face="custom" class="img-responsive"> + </div> + <div class="card-header"> + <div class="card-title h5">Custom</div> + <div class="card-subtitle text-gray">(240x192 or 240x216 8 bit web palette)</div> + </div> + <div class="card-body"> + <div class="form-group"> + <div class="col-3"> + <label class="form-label" for="customfile">Upload</label> + </div> + <div class="col-9"> + <input class="form-input" id="customfile" type="file"> + </div> + </div> + <div class="form-group"> + <label class="form-switch"> + <input type="checkbox" id="cusom16bit"> + <i class="form-icon"></i> 16 bit images (look better, slower, not recommended) + </label> + </div> + <div class="form-group"> + <label class="form-label" for="customcolor">Clock color</label> + <select class="form-select" id="customcolor"> + <option value="#ffffff">White</option> + <option value="#000000">Black</option> + </select> + </div> + <div class="form-group"> + <label class="form-label" for="customlocation">Clock location</label> + <select class="form-select" id="customlocation"> + <option value="16,16,-1">Top Left</option> + <option value="50,16,1">Top Right</option> + <option value="16,131,-1">Bottom Left</option> + <option value="50,131,1">Bottom Right</option> + </select> + </div> + </div> + <div class="card-footer"> + <button id="customupload" class="btn btn-primary uploadbutton disabled" face="custom">Upload</button> + </div> + </div> +</div> +`; + + var btns = document.getElementsByClassName("uploadbutton"); + for (var i=0;i<btns.length;i++) { + // When the 'upload' button is clicked... + btns[i].addEventListener("click", function(btn) { + // build app text + var facenumber = btn.target.getAttribute("face"); + var face; + if (facenumber=="custom") { + var select = document.getElementById("customlocation"); + var pos = select.options[select.selectedIndex].value.split(",").map(x=>parseInt(x)); + select = document.getElementById("customcolor"); + var col = select.options[select.selectedIndex].value; + face = { + x : pos[0], + y : pos[1], + align: pos[2], + bpp : document.getElementById('cusom16bit').checked ? 16 : 8, + col : col + }; + } else { + face = faces[facenumber]; + } + var faceInfo = { + bpp : face.bpp, + x : face.x, + y : face.y, + align : face.align, + col : face.col + }; + var imgMode = faceInfo.bpp==16 ? "rgb565" : "web"; + var img = document.querySelector(`img[face='${facenumber}']`); + var imgString = imageconverter.imagetoString(img, {mode:imgMode, output:"raw", compression:false}); + // send finished app + sendCustomizedApp({ + storage:[ + {name:"imgclock.face.img", content:imgString}, + {name:"imgclock.face.json", content:JSON.stringify(faceInfo)}, + ] + }); + }); + } + // Custom image upload + document.getElementById('customfile').onchange = function (evt) { + var tgt = evt.target || window.event.srcElement, files = tgt.files; + if (FileReader && files && files.length) { + var fr = new FileReader(); + fr.onload = function () { + document.getElementById("customimage").src = fr.result; + document.getElementById('customupload').classList.remove("disabled"); + } + fr.readAsDataURL(files[0]); + } + } + + </script> + </body> +</html> diff --git a/apps/imgclock/explode.png b/apps/imgclock/explode.png new file mode 100644 index 000000000..546a9c980 Binary files /dev/null and b/apps/imgclock/explode.png differ diff --git a/apps/imgclock/thisisfine.png b/apps/imgclock/thisisfine.png new file mode 100644 index 000000000..a7be57043 Binary files /dev/null and b/apps/imgclock/thisisfine.png differ diff --git a/apps/impwclock/ChangeLog b/apps/impwclock/ChangeLog new file mode 100644 index 000000000..c6974d37c --- /dev/null +++ b/apps/impwclock/ChangeLog @@ -0,0 +1,2 @@ +0.01: New App! +0.02: Stopped watchface from flashing every interval diff --git a/apps/impwclock/README.md b/apps/impwclock/README.md new file mode 100644 index 000000000..30e42c95e --- /dev/null +++ b/apps/impwclock/README.md @@ -0,0 +1,4 @@ +# Imprecise Word Clock + +This clock tells time in very rough approximation, as in "Late morning" or "Early afternoon." Good for vacations and weekends. Press button 1 to see the time in accurate, digital form. But do you really need to know the exact time? + diff --git a/apps/impwclock/clock-impword-icon.js b/apps/impwclock/clock-impword-icon.js new file mode 100644 index 000000000..f5ed47f1f --- /dev/null +++ b/apps/impwclock/clock-impword-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkEIf4A3iIBEn8ggP//8wgX/+cQl8Agc/BQPyCokQgHzmEB+ET+EfmMj+AXCmABBF4MBiIABiEC+PxC4Uwn4NB+QXMBAMzI4UxmYOBC5sfCgIvBgPzF4cfC5BgCFAMPkPwiXzL4cPmMvkAXDPAnzEgMxR4wDCGITl/AH4ApgUQbIICBAgXwBYMD+UAYoP/l4CBiUhd4QXFgIXCh73BfQUfAgIPBC4cQiIACC4cvj4PBC5AuCC48zgcwC4ZHBC5sBCAIEBF5EAC4RgDCQItCPAIXLCoQBBFgM/IoZHER4QA/AH4Anj8wgXzgX/+cQWoPyYQK9Bn/zj/wb4MTCAMf+MDAYMxkfwj8BmYXBmEzCYMf+cDmPzkMvj8zAIM/eoPyC4fy+IXDl8TmfwI4UvmYABAwIXB//xgPwBIIXCgYFBmEP/8fh/yF4sDC4QjBC4RvBF4UPB4JUBL4kAn8ROIJbBC4IIBL4hDBmaPEgBuB+EB+aPCUQUjCALn/AH4A/A")) \ No newline at end of file diff --git a/apps/impwclock/clock-impword.js b/apps/impwclock/clock-impword.js new file mode 100644 index 000000000..94b92b778 --- /dev/null +++ b/apps/impwclock/clock-impword.js @@ -0,0 +1,165 @@ +/* Imprecise Word Clock - A. Blanton +A remix of word clock +by Gordon Williams https://github.com/gfwilliams +- Changes the representation of time to be more general +- Shows accurate digital time when button 1 is pressed +*/ +/* jshint esversion: 6 */ + +const allWords = [ + "AEARLYDN", + "LATEYRZO", + "MORNINGO", + "KMIDDLEN", + "AFTERDAY", + "OFDZTHEC", + "EVENINGR", + "ORMNIGHT" +]; + + +const timeOfDay = { + 0: ["", 0, 0], + 1: ["EARLYMORNING", 10, 20, 30, 40, 50, 02, 12, 22, 32, 42, 52, 62], + 2: ["MORNING", 02, 12, 22, 32, 42, 52, 62], + 3: ["LATEMORNING", 01, 11, 21, 31, 02, 12, 22, 32, 42, 52, 62], + 4: ["MIDDAY", 13, 23, 33, 54, 64, 74], + 5: ["EARLYAFTERNOON", 10, 20, 30, 40, 50, 04, 14, 24, 34, 44, 70, 71, 72, 73], + 6: ["AFTERNOON", 04, 14, 24, 34, 44, 70, 71, 72, 73], + 7: ["LATEAFTERNOON", 01, 11, 21, 31, 04, 14, 24, 34, 44, 70, 71, 72, 73], + 8: ["EARLYEVENING", 10, 20, 30, 40, 50, 06, 16, 26, 36, 46, 56, 66], + 9: ["EVENING", 06, 16, 26, 36, 46, 56, 66], + 10: ["NIGHT", 37, 47, 57, 67, 77], + 11: ["MIDDLEOFTHENIGHT", 13, 23, 33, 43, 53, 63, 05, 15, 45, 55, 65, 37,47,57,67,77 ], +}; + + +// offsets and increments +const xs = 35; +const ys = 31; +const dy = 22; +const dx = 25; + +// font size and color +const fontSize = 3; // "6x8" +const passivColor = 0x3186 /*grey*/ ; +const activeColorNight = 0xF800 /*red*/ ; +const activeColorDay = 0xFFFF /* white */; + +var hidxPrev; + +function drawWordClock() { + + + // get time + var t = new Date(); + var h = t.getHours(); + var m = t.getMinutes(); + var time = ("0" + h).substr(-2) + ":" + ("0" + m).substr(-2); + var day = t.getDay(); + + var hidx; + + var activeColor = activeColorDay; + if(h < 7 || h > 19) {activeColor = activeColorNight;} + + g.setFont("6x8",fontSize); + g.setColor(passivColor); + g.setFontAlign(0, -1, 0); + + + // Switch case isn't good for this in Js apparently so... + if(h < 3){ + // Middle of the Night + hidx = 11; + } + else if (h < 7){ + // Early Morning + hidx = 1; + } + else if (h < 10){ + // Morning + hidx = 2; + } + else if (h < 12){ + // Late Morning + hidx = 3; + } + else if (h < 13){ + // Midday + hidx = 4; + } + else if (h < 14){ + // Early afternoon + hidx = 5; + } + else if (h < 16){ + // Afternoon + hidx = 6; + } + else if (h < 17){ + // Late Afternoon + hidx = 7; + } + else if (h < 19){ + // Early evening + hidx = 8; + } + else if (h < 21){ + // evening + hidx = 9; + } + else if (h < 24){ + // Night + hidx = 10; + } + + // check whether we need to redraw the watchface + if (hidx !== hidxPrev) { + // draw allWords + var c; + var y = ys; + var x = xs; + allWords.forEach((line) => { + x = xs; + for (c in line) { + g.drawString(line[c], x, y); + x += dx; + } + y += dy; + }); + + // write hour in active color + g.setColor(activeColor); + timeOfDay[hidx][0].split('').forEach((c, pos) => { + x = xs + (timeOfDay[hidx][pos + 1] / 10 | 0) * dx; + y = ys + (timeOfDay[hidx][pos + 1] % 10) * dy; + g.drawString(c, x, y); + }); + hidxPrev = hidx; + } + + // Display digital time while button 1 is pressed + g.clearRect(0, 215, 240, 240); + if (BTN1.read()){ + g.setColor(activeColor); + g.drawString(time, 120, 215); + } +} + + +Bangle.on('lcdPower', function(on) { + if (on) drawWordClock(); +}); + +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +setInterval(drawWordClock, 1E4); +drawWordClock(); + +// Show digital time while top button is pressed +setWatch(drawWordClock, BTN1, {repeat:true,edge:"both"}); + +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); diff --git a/apps/impwclock/clock-impword.png b/apps/impwclock/clock-impword.png new file mode 100644 index 000000000..e7ed0e828 Binary files /dev/null and b/apps/impwclock/clock-impword.png differ diff --git a/apps/jbells/ChangeLog b/apps/jbells/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/jbells/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/jbells/jbells.js b/apps/jbells/jbells.js index faab3defd..1da78f5f1 100644 --- a/apps/jbells/jbells.js +++ b/apps/jbells/jbells.js @@ -3,19 +3,19 @@ E.showMessage("Jingle Bells"); var eventEmitter = new Object(); function strofa(notes, times, current, next){ -eventEmitter.on(current, () => { + eventEmitter.on(current, () => { if (notes.length == 0) { - eventEmitter.emit(next); - return; + eventEmitter.emit(next); + return; } let note = notes.shift(); let time = times.shift(); Bangle.beep(time, note).then(() => { - setTimeout(() => { + setTimeout(() => { eventEmitter.emit(current); - }, time); + }, time); }); -}); + }); } var one = [2637, 2637, 2637, 2637, 2637, 2637, 2637, 3135, 2093, 2349, 2637]; diff --git a/apps/jbm8b/ChangeLog b/apps/jbm8b/ChangeLog new file mode 100644 index 000000000..80d7de1d6 --- /dev/null +++ b/apps/jbm8b/ChangeLog @@ -0,0 +1,3 @@ +0.01: First working version +0.02: Added delay in replying for dramatic effect +0.03: Fixed apps.json entry diff --git a/apps/jbm8b/app-icon.js b/apps/jbm8b/app-icon.js new file mode 100644 index 000000000..09bf032a6 --- /dev/null +++ b/apps/jbm8b/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwhBC/AGMrq2B1gAEwNWlYthq2s64AKGYIydFpoAEGLUrFqIADqxcXFqhiDFymBFy7GCF1owTRjCSVlYudeiGsF7/XlaNqSKBeP1mBwJxQMBReO1gaEleBMDBLN1hAC1hhBAoIwNCwQAGlZINqxvFGAIXOSBAXQN4hPBC5yQIVBxfBCAgvQSBC+NFAYRDMwJHOF654DqxkBYooALF6+sbIhkEF8Z3CRIWBR6AvXFAzvQF6wnIYQJgNd5AWNdoLoGBBAvPO5pfYH4IvUUwS/GVBzXBYCpHCq2s1mBDwKOWDwRgNPAwVVMCRLCwIABCZ6OJJSAATLxZgRACJeLAAMrFz9WFxiRgRpoADwIub1guQGDmsXhqSfRiL0G1jqkMRYxRwKLUGK2sFryVEq2B1gAEwNWFkIA/AH4A/AH4AQ")) \ No newline at end of file diff --git a/apps/jbm8b/app.js b/apps/jbm8b/app.js new file mode 100644 index 000000000..53baa32e3 --- /dev/null +++ b/apps/jbm8b/app.js @@ -0,0 +1,80 @@ +const affirmative = [ + 'It is\ncertain.', + 'It is\ndicededly\nso.', + 'Without\na doubt.', + 'Yes\ndefinitely.', + 'You may\nrely\non it.', + 'As I see,\nit yes.', + 'Most\nlikely.', + 'Outlook\ngood.', + 'Yes.', + 'Signs point\nto yes.' +]; +const nonCommittal = [ + 'Reply hazy,\ntry again.', + 'Ask again\nlater.', + 'Better not\ntell you\nnow.', + 'Cannot\npredict\nnow.', + 'Concentrate\nand\nask again.' +]; +const negative = [ + 'Don\'t\ncount on it.', + 'My reply\nis no.', + 'My sources\nsay no.', + 'Outlook\nis not\nso\ngood.', + 'Very\ndoubtful.' +]; + +const title = 'Magic 8 Ball'; + +const answers = [affirmative, nonCommittal, negative]; + +function getRandomArbitrary(min, max) { + return Math.random() * (max - min) + min; +} + +function predict() { + // affirmative, negative or non-committal + let max = answers.length; + const a = Math.floor(getRandomArbitrary(0, max)); + // sets max compared to answer category + max = answers[a].length; + const b = Math.floor(getRandomArbitrary(0, max)); + // get the answer + const response = answers[a][b]; + return response; +} + +function draw(msg) { + // console.log(msg); + g.clear(); + E.showMessage(msg, title); +} + +function reply(button) { + const theButton = (typeof button === 'undefined' || isNaN(button)) ? 1 : button; + const timer = Math.floor(getRandomArbitrary(0, theButton) * 1000); + // Thinking... + draw('...'); + setTimeout('draw(predict());', timer); +} + +function ask() { + draw('Ask me a\nYes or No\nquestion\nand\ntouch the\nscreen'); +} + +g.clear(); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); +ask(); + +// Event Handlers + +Bangle.on('touch', (button) => reply(button)); + +setWatch(ask, BTN1, { repeat: true, edge: "falling" }); +setWatch(reply, BTN3, { repeat: true, edge: "falling" }); + +// Back to launcher +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); \ No newline at end of file diff --git a/apps/jbm8b/app.png b/apps/jbm8b/app.png new file mode 100644 index 000000000..24c3013de Binary files /dev/null and b/apps/jbm8b/app.png differ diff --git a/apps/largeclock/ChangeLog b/apps/largeclock/ChangeLog new file mode 100644 index 000000000..091f7d65b --- /dev/null +++ b/apps/largeclock/ChangeLog @@ -0,0 +1,6 @@ +0.01: Init +0.02: fix 3/4 moon orientation +0.03: Change `largeclock.json` to 'data' file to allow settings to be preserved +0.04: Adjust layout to account for new vector font +0.05: Add support for 12 hour time +0.06: Allow to disable BTN1 and BTN3 buttons diff --git a/apps/largeclock/README.md b/apps/largeclock/README.md new file mode 100644 index 000000000..5c2ad42c2 --- /dev/null +++ b/apps/largeclock/README.md @@ -0,0 +1,19 @@ +# Large clock + +A readable and informational digital watch, with date, seconds and moon phase and with programmable BTN1 & BTN3 + +## Features + +- Readable +- Informative: hours, minutes, secondsa, date, year and moon phase +- Pairs nicely with any other apps: in setting > large clock any installed app can be assigned to BTN1 and BTN3 in order to open it easily directly from the watch, without the hassle of passing trough the launcher. For example BTN1 can be assigned to alarm and BTN3 to chronometer. + +## How to use it + +- The clock can be used as any other one, if you like it just set it as the default clock app in settings > select clock +- In setting > large clock you can select which app, if any, is to be open by BTN1 and BTN3 + +## Credits + +- The clock face is heavily inspired by Big Clock byJeffmer https://jeffmer.github.io/JeffsBangleAppsDev/ +- The moon phase is basically the one from the widget https://github.com/espruino/BangleApps/tree/master/apps/widmp diff --git a/apps/largeclock/largeclock-icon.js b/apps/largeclock/largeclock-icon.js new file mode 100644 index 000000000..22aadc576 --- /dev/null +++ b/apps/largeclock/largeclock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AH4ArmYAQCwkDC6MwFyowFC/4XKnGIAAIQFBAWDC5INCBwggEEIYXdxAODnAYCAYIgDDAQXECoIrDE4YrEBwYX/C/4X/C/4X8BwIKBAAM4DgQDBBAQDBBAIXFE4QOCA4QrCAAQHCC7wODCwYhEEAYXGACAX/C5cDCyMwC4YwSCwgA/AH4AlA=")) diff --git a/apps/largeclock/largeclock.js b/apps/largeclock/largeclock.js new file mode 100644 index 000000000..6f3d638fa --- /dev/null +++ b/apps/largeclock/largeclock.js @@ -0,0 +1,206 @@ +const REFRESH_RATE = 1000; + +let interval; +let lastMoonPhase; +let lastMinutes; + +const is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; + +const moonR = 12; +const moonX = 215; +const moonY = is12Hour ? 90 : 50; + +const settings = require("Storage").readJSON("largeclock.json", 1)||{}; +const BTN1app = settings.BTN1 || ""; +const BTN3app = settings.BTN3 || ""; + +function drawMoon(d) { + const BLACK = 0, + MOON = 0x41f, + MC = 29.5305882, + NM = 694039.09; + + var moon = { + // reset + 0: () => { + g.setColor(BLACK).fillRect( + moonX - moonR, + moonY - moonR, + moonX + moonR, + moonY + moonR + ); + }, + // new moon + 1: () => { + moon[0](); + g.setColor(MOON).drawCircle(moonX, moonY, moonR); + }, + // 1/4 ascending + 2: () => { + moon[3](); + g.setColor(BLACK).fillEllipse( + moonX - moonR / 2, + moonY - moonR, + moonX + moonR / 2, + moonY + moonR + ); + }, + // 1/2 ascending + 3: () => { + moon[0](); + g.setColor(MOON) + .fillCircle(moonX, moonY, moonR) + .setColor(BLACK) + .fillRect(moonX, moonY - moonR, moonX + moonR + moonR, moonY + moonR); + }, + // 3/4 ascending + 4: () => { + moon[3](); + g.setColor(MOON).fillEllipse( + moonX - moonR / 2, + moonY - moonR, + moonX + moonR / 2, + moonY + moonR + ); + }, + // Full moon + 5: () => { + moon[0](); + g.setColor(MOON).fillCircle(moonX, moonY, moonR); + }, + // 3/4 descending + 6: () => { + moon[7](); + g.setColor(MOON).fillEllipse( + moonX - moonR / 2, + moonY - moonR, + moonX + moonR / 2, + moonY + moonR + ); + }, + // 1/2 descending + 7: () => { + moon[0](); + g.setColor(MOON) + .fillCircle(moonX, moonY, moonR) + .setColor(BLACK) + .fillRect(moonX - moonR, moonY - moonR, moonX, moonY + moonR); + }, + // 1/4 descending + 8: () => { + moon[7](); + g.setColor(BLACK).fillEllipse( + moonX - moonR / 2, + moonY - moonR, + moonX + moonR / 2, + moonY + moonR + ); + } + }; + + function moonPhase(d) { + var tmp, + month = d.getMonth(), + year = d.getFullYear(), + day = d.getDate(); + if (month < 3) { + year--; + month += 12; + } + tmp = (365.25 * year + 30.6 * ++month + day - NM) / MC; + return Math.round((tmp - (tmp | 0)) * 7 + 1); + } + + const currentMoonPhase = moonPhase(d); + if (currentMoonPhase != lastMoonPhase) { + moon[currentMoonPhase](); + lastMoonPhase = currentMoonPhase; + } +} + +function drawTime(d) { + const da = d.toString().split(" "); + const time = da[4].split(":"); + const dow = da[0]; + const month = da[1]; + const day = da[2]; + const year = da[3]; + const hours = is12Hour ? ("0" + (((d.getHours() + 11) % 12) + 1)).substr(-2) : time[0]; + const meridian = d.getHours() < 12 ? "AM" : "PM"; + const minutes = time[1]; + const seconds = time[2]; + if (minutes != lastMinutes) { + if (is12Hour) { + g.setFont("Vector", 18); + g.setColor(1, 1, 1); + g.setFontAlign(0, -1); + g.clearRect(195, 34, 240, 44); + g.drawString(meridian, 217, 34); + } + g.clearRect(0, 24, moonX - moonR - 10, 239); + g.setColor(1, 1, 1); + g.setFontAlign(-1, -1); + g.setFont("Vector", 100); + g.drawString(hours, 40, 24, true); + g.setColor(1, 50, 1); + g.drawString(minutes, 40, 135, true); + g.setFont("Vector", 20); + g.setRotation(3); + g.drawString(`${dow} ${day} ${month}`, 50, 10, true); + g.drawString(year, is12Hour ? 46 : 75, 205, true); + lastMinutes = minutes; + } + g.setRotation(0); + g.setFont("Vector", 20); + g.setColor(1, 1, 1); + g.setFontAlign(0, -1); + g.clearRect(195, 210, 240, 240); + g.drawString(seconds, 215, 215); +} + +function drawClockFace() { + const d = new Date(); + drawTime(d); + drawMoon(d); +} + +Bangle.on("lcdPower", function(on) { + if (on) { + g.clear(); + Bangle.drawWidgets(); + drawClockFace(); + interval = setInterval(drawClockFace, REFRESH_RATE); + } else { + clearInterval(interval); + lastMinutes = undefined; + lastMoonPhase = undefined; + } +}); + +Bangle.setLCDMode(); + +// Show launcher when middle button pressed +clearWatch(); +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +if (BTN1app) setWatch( + function() { + load(BTN1app); + }, + BTN1, + { repeat: false, edge: "rising" } +); +if (BTN3app) setWatch( + function() { + load(BTN3app); + }, + BTN3, + { repeat: false, edge: "rising" } +); + +g.clear(); +clearInterval(); +drawClockFace(); +interval = setInterval(drawClockFace, REFRESH_RATE); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); diff --git a/apps/largeclock/largeclock.json b/apps/largeclock/largeclock.json new file mode 100644 index 000000000..58c981197 --- /dev/null +++ b/apps/largeclock/largeclock.json @@ -0,0 +1,4 @@ +{ + "BTN1": "", + "BTN3": "" +} diff --git a/apps/largeclock/largeclock.png b/apps/largeclock/largeclock.png new file mode 100644 index 000000000..32e87e768 Binary files /dev/null and b/apps/largeclock/largeclock.png differ diff --git a/apps/largeclock/settings.js b/apps/largeclock/settings.js new file mode 100644 index 000000000..293f66677 --- /dev/null +++ b/apps/largeclock/settings.js @@ -0,0 +1,76 @@ +(function(back) { + const s = require("Storage"); + const apps = s + .list(/\.info$/) + .map(app => { + var a = s.readJSON(app, 1); + return ( + a && { + n: a.name, + t: a.type, + src: a.src + } + ); + }) + .filter(app => app && (app.t == "app" || app.t == "clock" || !app.t)) + .map(a => { + return { n: a.n, src: a.src }; + }); + apps.sort((a, b) => { + if (a.n < b.n) return -1; + if (a.n > b.n) return 1; + return 0; + }); + apps.push({ + n: "NONE", + src: "" + }); + + const settings = s.readJSON("largeclock.json", 1) || { + BTN1: "", + BTN3: "" + }; + + function showApps(btn) { + function format(v) { + return v === settings[btn] ? "*" : ""; + } + + function onchange(v) { + settings[btn] = v; + s.writeJSON("largeclock.json", settings); + } + + const btnMenu = { + "": { + title: `Apps for ${btn}` + }, + "< Back": () => E.showMenu(mainMenu) + }; + + if (apps.length > 0) { + for (let i = 0; i < apps.length; i++) { + btnMenu[apps[i].n] = { + value: apps[i].src, + format: format, + onchange: onchange + }; + } + } else { + btnMenu["...No Apps..."] = { + value: undefined, + format: () => "", + onchange: () => {} + }; + } + return E.showMenu(btnMenu); + } + + const mainMenu = { + "": { title: "Large Clock Settings" }, + "< Back": back, + "BTN1 app": () => showApps("BTN1"), + "BTN3 app": () => showApps("BTN3") + }; + E.showMenu(mainMenu); +}); diff --git a/apps/launch/ChangeLog b/apps/launch/ChangeLog index 9e4a1eaf3..7e7ea65ab 100644 --- a/apps/launch/ChangeLog +++ b/apps/launch/ChangeLog @@ -1,2 +1,4 @@ 0.01: New App! 0.02: Only store relevant app data (saves RAM when many apps) +0.03: Allow scrolling to wrap around (fix #382) +0.04: Now displays widgets diff --git a/apps/launch/app.js b/apps/launch/app.js index a256b6909..9795d8901 100644 --- a/apps/launch/app.js +++ b/apps/launch/app.js @@ -1,5 +1,5 @@ var s = require("Storage"); -var apps = s.list(/\.info$/).map(app=>{var a=s.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src}}).filter(app=>app && (app.type=="app" || app.type=="clock" || !app.type)); +var apps = s.list(/\.info$/).map(app=>{var a=s.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src};}).filter(app=>app && (app.type=="app" || app.type=="clock" || !app.type)); apps.sort((a,b)=>{ var n=(0|a.sortorder)-(0|b.sortorder); if (n) return n; // do sortorder first @@ -17,10 +17,13 @@ function drawMenu() { var n = 3; if (selected>=n+menuScroll) menuScroll = 1+selected-n; if (selected<menuScroll) menuScroll = selected; - if (menuScroll) g.fillPoly([120,0,100,20,140,20]); - else g.clearRect(100,0,140,20); - if (apps.length>n+menuScroll) g.fillPoly([120,239,100,219,140,219]); - else g.clearRect(100,219,140,239); + // arrows + g.setColor(menuScroll ? -1 : 0); + g.fillPoly([120,6,106,20,134,20]); + g.setColor((apps.length>n+menuScroll) ? -1 : 0); + g.fillPoly([120,233,106,219,134,219]); + // draw + g.setColor(-1); for (var i=0;i<n;i++) { var app = apps[i+menuScroll]; if (!app) break; @@ -40,16 +43,14 @@ function drawMenu() { } drawMenu(); setWatch(function() { - if (selected>0) { - selected--; - drawMenu(); - } + selected--; + if (selected<0) selected = apps.length-1; + drawMenu(); }, BTN1, {repeat:true}); setWatch(function() { - if (selected+1<apps.length) { - selected++; - drawMenu(); - } + selected++; + if (selected>=apps.length) selected = 0; + drawMenu(); }, BTN3, {repeat:true}); setWatch(function() { // run if (!apps[selected].src) return; @@ -61,3 +62,5 @@ setWatch(function() { // run load(apps[selected].src); } }, BTN2, {repeat:true,edge:"falling"}); +Bangle.loadWidgets(); +Bangle.drawWidgets(); diff --git a/apps/life/ChangeLog b/apps/life/ChangeLog new file mode 100644 index 000000000..ca105e8fa --- /dev/null +++ b/apps/life/ChangeLog @@ -0,0 +1,5 @@ +0.01: New App! +0.02: Updated to be more responsive re suggestion by Gordon +0.03: fix start & reset, chang eperiod to 65ms, remove timing info +0.04: fix default parameter, replace timing + diff --git a/apps/life/life-icon.js b/apps/life/life-icon.js new file mode 100644 index 000000000..8127abd79 --- /dev/null +++ b/apps/life/life-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AFkLC6+wC6u73YuVC7JIUCwIZBLywwTIwYwTC4QwUC4OwGCgXCCoQwRXwYwTO4wwQO4wwQO44wPO44wPO5G7olACY9EAAVLO44LCCosECwYXDGAm0BQIvFCwoABCwIcCCoQuHCwwXEAAguFBQgFBoEEC451GIwQVDAgIXBIhQwECoYEBYAS5NCogEBC6BGFVAQXPGAoXRGAoXSO6owGC6Z3VGAoXUd4gWRGAYXVIwQXUIwReSC7gWUgELFyoXBCyoA/ACwA==")) \ No newline at end of file diff --git a/apps/life/life.js b/apps/life/life.js new file mode 100644 index 000000000..6ff8a40be --- /dev/null +++ b/apps/life/life.js @@ -0,0 +1,130 @@ +Bangle.setLCDTimeout(30); + +var buf = Graphics.createArrayBuffer(160,160,1,{msb:true}); + +function flip() { + g.setColor(1,1,1); + g.drawImage({width:160,height:160,bpp:1,buffer:buf.buffer},40,40); + buf.clear(); +} + +var genA = new Uint8Array(324); +var genB = new Uint8Array(324); +var generation=0; +var gentime=0; +var currentY=1; + +function initDraw(gen){ + for (let y = 1; y<17; ++y) + for (let x = 1; x<17; ++x) { + var r = Math.random()<0.5?1:0; + gen[x+y*18] = r; + if (r==1){ + var Xr=10*(x-1); + var Yr=10*(y-1); + buf.fillRect(Xr,Yr, Xr+7,Yr+7); + } + } + flip(); +} + +function howlong(){ + ++generation; + g.setFont("6x8",2); + g.setFontAlign(-1,-1,0); + gentime = Math.floor(gentime); + g.drawString('Gen:'+generation+' '+gentime+'ms ',20,220,true); + gentime=0; +} + +function next(){ + "ram"; + var start = Date.now(); + var cur=genA, fut=genB, y=currentY; + var count=(p)=>{return cur[p-19]+cur[p-18]+cur[p-17]+cur[p-1]+cur[p+1]+cur[p+17]+cur[p+18]+cur[p+19];}; + for (let x = 1; x<17; ++x){ + var ind = x+y*18; + var nc = count(ind); + var r = (cur[ind]==1 && nc==2 || nc==3)?1:0; + fut[ind]=r; + if (r==1){ + var Xr=10*(x-1); + var Yr=10*(y-1); + buf.fillRect(Xr,Yr, Xr+7,Yr+7); + } + } + gentime+=(Date.now()-start); + if (y==16){ + flip(); + var tmp = genA; genA=genB; genB=tmp; + howlong(); + currentY=1; + } else ++currentY; +} + + +var intervalRef = null; + +function stopdraw() { + if(intervalRef) {clearInterval(intervalRef);} + } + +function startdraw(init) { + if (init===undefined) init=false; + if(!init) g.clear(); + Bangle.drawWidgets(); + g.reset(); + g.setColor(1,1,1); + g.setFont("6x8",1); + g.setFontAlign(0,0,3); + g.drawString("RESET",230,200); + g.drawString("LAUNCH",230,130); + g.drawString("CLOCK",230,60); + if(!init) intervalRef = setInterval(next,65); + } + +function regen(){ + stopdraw(); + g.setColor(1,1,1); + initDraw(genA); + currentY=1; + generation = 0; + gentime=0; + intervalRef = setInterval(next,65); +} + + function setButtons(){ + setWatch(()=>{load();}, BTN1, {repeat:false,edge:"falling"}); + setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); + setWatch(regen, BTN3, {repeat:true,edge:"rising"}); + } + + var SCREENACCESS = { + withApp:true, + request:function(){ + this.withApp=false; + stopdraw(); + clearWatch(); + }, + release:function(){ + this.withApp=true; + startdraw(); + setButtons(); + } + }; + + Bangle.on('lcdPower',function(on) { + if (!SCREENACCESS.withApp) return; + if (on) { + startdraw(); + } else { + stopdraw(); + } + }); + + g.clear(); + Bangle.loadWidgets(); + regen(); + startdraw(true); + setButtons(); + \ No newline at end of file diff --git a/apps/life/life.min.js b/apps/life/life.min.js new file mode 100644 index 000000000..42a2e6515 --- /dev/null +++ b/apps/life/life.min.js @@ -0,0 +1,5 @@ +Bangle.setLCDTimeout(30);var buf=Graphics.createArrayBuffer(160,160,1,{msb:!0});function flip(){g.setColor(1,1,1);g.drawImage({width:160,height:160,bpp:1,buffer:buf.buffer},40,40);buf.clear()}var genA=new Uint8Array(324),genB=new Uint8Array(324),generation=0,gentime=0,currentY=1;function initDraw(c){for(var a=1;17>a;++a)for(var h=1;17>h;++h){var d=.5>Math.random()?1:0;c[h+18*a]=d;if(1==d){d=10*(h-1);var f=10*(a-1);buf.fillRect(d,f,d+7,f+7)}}flip()} +function howlong(){++generation;g.setFont("6x8",2);g.setFontAlign(-1,-1,0);gentime=Math.floor(gentime);g.drawString("Gen:"+generation+" "+gentime+"ms ",20,220,!0);gentime=0} +function next(){"ram";for(var c=Date.now(),a=genA,h=genB,d=currentY,f=1;17>f;++f){var b=f+18*d,e=a[b-19]+a[b-18]+a[b-17]+a[b-1]+a[b+1]+a[b+17]+a[b+18]+a[b+19];e=1==a[b]&&2==e||3==e?1:0;h[b]=e;1==e&&(b=10*(f-1),e=10*(d-1),buf.fillRect(b,e,b+7,e+7))}gentime+=Date.now()-c;16==d?(flip(),c=genA,genA=genB,genB=c,howlong(),currentY=1):++currentY}var intervalRef=null;function stopdraw(){intervalRef&&clearInterval(intervalRef)} +function startdraw(c){void 0===c&&(c=!1);c||g.clear();Bangle.drawWidgets();g.reset();g.setColor(1,1,1);g.setFont("6x8",1);g.setFontAlign(0,0,3);g.drawString("RESET",230,200);g.drawString("LAUNCH",230,130);g.drawString("CLOCK",230,60);c||(intervalRef=setInterval(next,65))}function regen(){stopdraw();g.setColor(1,1,1);initDraw(genA);currentY=1;gentime=generation=0;intervalRef=setInterval(next,65)} +function setButtons(){setWatch(function(){load()},BTN1,{repeat:!1,edge:"falling"});setWatch(Bangle.showLauncher,BTN2,{repeat:!1,edge:"falling"});setWatch(regen,BTN3,{repeat:!0,edge:"rising"})}var SCREENACCESS={withApp:!0,request:function(){this.withApp=!1;stopdraw();clearWatch()},release:function(){this.withApp=!0;startdraw();setButtons()}};Bangle.on("lcdPower",function(c){SCREENACCESS.withApp&&(c?startdraw():stopdraw())});g.clear();Bangle.loadWidgets();regen();startdraw(!0);setButtons(); diff --git a/apps/life/life.png b/apps/life/life.png new file mode 100644 index 000000000..a88157f5c Binary files /dev/null and b/apps/life/life.png differ diff --git a/apps/locale/ChangeLog b/apps/locale/ChangeLog index 3d983150d..8338f9f84 100644 --- a/apps/locale/ChangeLog +++ b/apps/locale/ChangeLog @@ -6,3 +6,4 @@ Add correct scaling for speed/distance/temperature 0.06: Remove translations if not required Ensure 'on' is always supplied for translations +0.07: Improve handling of non-ASCII characters (fix #469) diff --git a/apps/locale/README.md b/apps/locale/README.md new file mode 100644 index 000000000..fd43c2825 --- /dev/null +++ b/apps/locale/README.md @@ -0,0 +1,29 @@ +# Languages (locale) + +Country-specific app internationalisation. + +This is not an app, but instead it is a library that can be used by +other applications or widgets to display messages. + +## Usage + +Some menus that pop up are translated automatically, but if you're +writing an application you can use the `locale` library to +do all the translation for you. + +See https://www.espruino.com/Bangle.js+Locale for full examples. + +```JS +// Date to date string (long) +>require('locale').date(new Date()) +="Donnerstag, 02. April 2020" + +// Date to date string (short) +>require('locale').date(new Date(),1) +="02.04.2020" +``` + +Bangle.js has a `locale` library built in that is just a standard +British English (`en_GB`) localisation - so you can use `locale` +in your apps without requiring users to have this Language library +installed. diff --git a/apps/locale/locale.html b/apps/locale/locale.html index 21bf37f29..2389203bb 100644 --- a/apps/locale/locale.html +++ b/apps/locale/locale.html @@ -1,5 +1,6 @@ <html> <head> + <meta charset="UTF-8"> <link rel="stylesheet" href="../../css/spectre.min.css"> </head> <body> @@ -11,8 +12,8 @@ </div> <p>Then click <button id="upload" class="btn btn-primary">Upload</button></p> - <script src="../../lib/customize.js"></script> - <script src="locales.js"></script> + <script src="../../core/lib/customize.js"></script> + <script src="locales.js" charset="utf-8"></script> <script> /* @@ -45,7 +46,23 @@ exports = { name : "en_GB", currencySym:"£", }; */ - + function codePageLookup(lang, codePage, ch) { + var chCode = ch.charCodeAt(); + if (chCode>=32 && chCode<128) return ch; // ASCII - copy it + // not normal ASCII + var n; // default is a space + if (codePage.map.indexOf(ch)>=0) // look up in char map, escape that + n = 128+codePage.map.indexOf(ch); + /*else if (chCode<256) // it's non-ascii, but <256 - just escape it + n = chCode;*/ + else { + if (charFallbacks[ch]) return charFallbacks[ch]; + console.error(`Locale ${lang}: Character ${ch} (${chCode}) is not in Code Page ${codePage.name}`); + return undefined; + } + // escape the char + return '\\x'+(n+256).toString(16).slice(-2); + } // do some sanity checks Object.keys(locales).forEach(function(localeName) { @@ -54,6 +71,22 @@ exports = { name : "en_GB", currencySym:"£", if (distanceUnits[locale.distance[0]]===undefined) console.error(localeName+": Unknown distance unit "+locale.distance[0]); if (distanceUnits[locale.distance[1]]===undefined) console.error(localeName+": Unknown distance unit "+locale.distance[1]); if (speedUnits[locale.speed]===undefined) console.error(localeName+": Unknown speed unit "+locale.speed); + if (locale.temperature!='°C' && locale.temperature!='°F') + console.error(localeName+": Unknown temperature unit "+locale.temperature); + // Now check that codepage is ok and all chars in translation are in that codepage + const codePageName = "ISO8859-1"; + if (locale.codePage) codePageName = locale.codePage; + const codePage = codePages[codePageName]; + if (codePage===undefined) console.error(localeName+": Unknown codePage "+codePageName); + function checkChars(v,path) { + if ("object"==typeof v) + Object.keys(v).forEach(k=>checkChars(v[k], path+"."+k)); + else if ("string"==typeof v) + for (var i=0;i<v.length;i++) + if (codePageLookup(localeName, codePage, v[i])===undefined) + console.error(` ... in ${path}[${i}]`); + } + checkChars(locale,localeName); }); var languageSelector = document.getElementById("languages"); @@ -68,40 +101,64 @@ exports = { name : "en_GB", currencySym:"£", document.getElementById("upload").addEventListener("click", function() { - var lang = languageSelector.options[languageSelector.selectedIndex].value; - console.log(lang); + const lang = languageSelector.options[languageSelector.selectedIndex].value; + console.log(`Language ${lang}`); - locale = locales[lang]; + const locale = locales[lang]; if (!locale) { - alert("Language not found!"); + alert(`Language ${lang} not found!`); return; } + const codePageName = "ISO8859-1"; + if (locale.codePage) + codePageName = locale.codePage; + const codePage = codePages[codePageName]; + if (!codePage) { + alert(`Code Page ${codePageName} not found!`); + return; + } - function js(x) { return JSON.stringify(x); } + // Convert object to JSON, with codepage + function js(x) { + // do nortmal conversion + x = JSON.stringify(x); + /* assume any out of bounds character is going to + be inside a quoted string */ + var s = ''; + for (var i=0;i<x.length;i++) { + var ch = codePageLookup(lang, codePage, x[i]); + s += (ch===undefined) ? "?" : ch; + } + return s; + } + + function unitConv(x) { + return x === 1 ? 'n' : 'n/' + x + } var replaceList = { "%Y": "d.getFullYear()", - "%y": "(d.getFullYear().toString()).substr(-2)", - "%m": "('0'+(d.getMonth()+1).toString()).substr(-2)", + "%y": "(d.getFullYear().toString()).slice(-2)", + "%m": "('0'+(d.getMonth()+1).toString()).slice(-2)", "%-m": "d.getMonth()+1", - "%d": "('0'+d.getDate()).substr(-2)", + "%d": "('0'+d.getDate()).slice(-2)", "%-d": "d.getDate()", - "%HH": "('0'+d.getHours()).substr(-2)", - "%MM": "('0'+d.getMinutes()).substr(-2)", - "%SS": "('0'+d.getSeconds()).substr(-2)", - "%A": "l.day.split(',')[d.getDay()]", - "%a": "l.abday.split(',')[d.getDay()]", - "%B": "l.month.split(',')[d.getMonth()]", - "%b": "l.abmonth.split(',')[d.getMonth()]", - "%p": `(d.getHours()<12)?${js(locale.ampm[0].toUpperCase())}:${js(locale.ampm[1].toUpperCase())}`, - "%P": `(d.getHours()<12)?${js(locale.ampm[0].toLowerCase())}:${js(locale.ampm[1].toLowerCase())}` + "%HH": "('0'+d.getHours()).slice(-2)", + "%MM": "('0'+d.getMinutes()).slice(-2)", + "%SS": "('0'+d.getSeconds()).slice(-2)", + "%A": "day.split(',')[d.getDay()]", + "%a": "day.split(',')[d.getDay() + 7]", + "%B": "month.split(',')[d.getMonth()]", + "%b": "month.split(',')[d.getMonth() + 12]", + "%p": `d.getHours()<12?${js(locale.ampm[0].toUpperCase())}:${js(locale.ampm[1].toUpperCase())}`, + "%P": `d.getHours()<12?${js(locale.ampm[0].toLowerCase())}:${js(locale.ampm[1].toLowerCase())}` }; - var timeN = locales[lang].timePattern[0]; - var timeS = locales[lang].timePattern[1]; - var dateN = locales[lang].datePattern[0]; - var dateS = locales[lang].datePattern[1]; + var timeN = locale.timePattern[0]; + var timeS = locale.timePattern[1]; + var dateN = locale.datePattern[0]; + var dateS = locale.datePattern[1]; Object.keys(replaceList).forEach(e => { timeN = timeN.replace(e,"${"+replaceList[e]+"}"); timeS = timeS.replace(e,"${"+replaceList[e]+"}"); @@ -109,45 +166,51 @@ exports = { name : "en_GB", currencySym:"£", dateS = dateS.replace(e,"${"+replaceList[e]+"}"); }); var currency = locale.currency_first ? - `${js(locale.currency_symbol)} + n.toFixed(2)`: - `n.toFixed(2) + ${js(locale.currency_symbol)}`; - var temperature; - if (locale.temperature=='°C') temperature="t"; - else if (locale.temperature=='°F') temperature="(t*9/5)+32"; - else throw new Error("Unknown temperature unit "+locale.temperature); + `${js(locale.currency_symbol)} + exports.number(n)`: + `exports.number(n) + ${js(locale.currency_symbol)}`; + var temperature = locale.temperature=='°F' ? '(t*9/5)+32' : 't'; - var localeModule = `var l = ${JSON.stringify({ - abday : locale.abday, - day : locale.day, - abmonth : locale.abmonth, - month : locale.month, - })}; -exports = { + var localeModule = ` +var day = ${js(locale.day + ',' + locale.abday)}; +var month = ${js(locale.month + ',' + locale.abmonth)}; +function round(n) { + return n < 10 ? Math.round(n * 10) / 10 : Math.round(n); +} +exports = { name: ${js(locale.lang)}, currencySym: ${js(locale.currency_symbol)}, - dow: (d,short) => {day = d.getDay();return (short) ? l.abday.split(",")[day] : l.day.split(",")[day];}, - month: (d,short) => { month = d.getMonth(); return (short) ? l.abmonth.split(",")[month] : l.month.split(",")[month];}, - number: n => n.toString(), + dow: (d,short) => day.split(',')[d.getDay() + (short ? 7 : 0)], + month: (d,short) => month.split(',')[d.getMonth() + (short ? 12 : 0)], + number: (n, dec) => { + if (dec == null) dec = 2; + var w = n.toFixed(dec), + k = w|0, + b = n < 0 ? 1 : 0, + u = Math.abs(w-k), + d = (''+u.toFixed(dec)).substr(2, dec), + s = ''+k, + i = s.length, + r = ''; + while ((i-=3) > b) { + r = '${locale.thousands_sep}' + s.substr(i, 3) + r; + } + return s.substr(0, i + 3) + r + (d ? '${locale.decimal_point}' + d: ''); + }, currency: n => ${currency}, - distance: n => (n < ${distanceUnits[locale.distance[1]]}) ? Math.round(n/${distanceUnits[locale.distance[0]]}) + ${js(locale.distance[0])} : Math.round(n/${distanceUnits[locale.distance[1]]}) + ${js(locale.distance[1])}, - speed: s => Math.round(s/${speedUnits[locale.speed]}) + ${js(locale.speed)}, + distance: n => n < ${distanceUnits[locale.distance[1]]} ? round(${unitConv(distanceUnits[locale.distance[0]])}) + ${js(locale.distance[0])} : round(${unitConv(distanceUnits[locale.distance[1]])}) + ${js(locale.distance[1])}, + speed: n => round(${unitConv(speedUnits[locale.speed])}) + ${js(locale.speed)}, temp: t => Math.round(${temperature}) + ${js(locale.temperature)}, - translate: s => ${locale.trans?`{var t=${js(locale.trans)};s=""+s;return t[s]||t[s.toLowerCase()]||s;}`:`s`}, - date: (d,short) => (short) ? \`${dateS}\`: \`${dateN}\`, - time: (d,short) => (short) ? \`${timeS}\`: \`${timeN}\`, - meridian: d => (d.getHours() <= 12) ? ${js(locale.ampm[0])}:${js(locale.ampm[1])}, -};`; -console.log("Locale Module is:",localeModule); -/* -FIXME: - -* Number/Currency need to add thousands separators: .replace(${js(locale.thousands_sep)}, ${js(locale.decimal_point)}) won't cut it as toString doesn't add separators itself -* distance (and speed) should probably use 1 decimal point for numbers less than 10 -*/ + translate: s => ${locale.trans?`{var t=${js(locale.trans)};s=''+s;return t[s]||t[s.toLowerCase()]||s;}`:`s`}, + date: (d,short) => short ? \`${dateS}\` : \`${dateN}\`, + time: (d,short) => short ? \`${timeS}\` : \`${timeN}\`, + meridian: d => d.getHours() < 12 ? ${js(locale.ampm[0])}:${js(locale.ampm[1])}, +}; +`.trim(); + console.log("Locale Module is:",localeModule); sendCustomizedApp({ storage:[ - {name:"locale", content:localeModule} + {name:"locale", url:"locale.js", content:localeModule} ] }); }); diff --git a/apps/locale/locales.js b/apps/locale/locales.js index 508c92015..fc7a545d7 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -1,15 +1,44 @@ /* jshint esversion: 6 */ const distanceUnits = { // how many meters per X? - "m": 1, - "yd": 0.9144, - "mi": 1609.34, - "km": 1000, - "kmi": 1000 + "m": 1, + "yd": 0.9144, + "mi": 1609.34, + "km": 1000, + "kmi": 1000 }; const speedUnits = { // how many kph per X? - "kmh": 1, - "kph": 1, - "mph": 1.60934 + "kmh": 1, + "kph": 1, + "km/h": 1, + "mph": 1.60934 +}; + +/* +For a codepage, 'map' is a map of char codes 128 and above. +Where there is no character, just use '.' +*/ +const codePages = { + "ISO8859-1" : { + name : "ISO8859-1", + map : ` +€.‚ƒ„…†‡ˆ‰Š‹Œ.Ž. +.‘’“”•–—˜™š›œ.žŸ +.¡¢£¤¥¦§¨©ª«¬.®¯ +°±²³´µ¶·¸¹º»¼½¾¿ +ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ +ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß +àáâãäåæçèéêëìíîï +ðñòóôõö÷øùúûüýþÿ +`.replace(/[ \n]/g,"") + } +}; +/* When it's not in the codepage, try and use +these conversions */ +const charFallbacks = { + "č":"c", + "ř":"r", + "ő":"o", + "ě":"e" }; /* @@ -33,417 +62,473 @@ timePattern / datePattern: */ var locales = { - "en_GB": { // this is default - lang: "en_GB", - decimal_point: ".", - thousands_sep: ",", - currency_symbol: "£", currency_first: true, - int_curr_symbol: "GBP", - speed: 'mph', - distance: { "0": "yd", "1": "mi" }, - temperature: '°C', - ampm: { 0: "am", 1: "pm" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%b %d %Y", 1: "%d/%m/%Y" }, // Feb 28 2020" // "01/03/2020"(short) - abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", - month: "January,February,March,April,May,June,July,August,September,October,November,December", - abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", - day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", - // No translation for english... - }, - "de_DE": { - lang: "de_DE", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "\x80", - int_curr_symbol: "EUR", - speed: "kmh", - distance: { 0: "m", 1: "km" }, - temperature: "°C", - ampm: { 0: "", 1: "" }, - timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, - datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%Y" }, // Sonntag, 1. März 2020 // 01.01.20 - abmonth: "Jan,Feb,Mär,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez", - month: "Januar,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember", - abday: "So,Mo,Di,Mi,Do,Fr,Sa", - day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag", - trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" } - }, - "en_US": { - lang: "en_US", - decimal_point: ".", - thousands_sep: ",", - currency_symbol: "$", currency_first: true, - int_curr_symbol: "USD", - speed: "mph", - distance: { 0: "yd", 1: "mi" }, - temperature: "°F", - ampm: { 0: "am", 1: "pm" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "", 1: "%m/%d/%y" }, - abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", - month: "January,February,March,April,May,June,July,August,September,October,November,December", - abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", - day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", - // No translation for english... - }, - "en_JP": { // we do not have the font, so it is not ja_JP - lang: "en_JP", - decimal_point: ".", - thousands_sep: ",", - currency_symbol: "¥", - int_curr_symbol: "JPY", - speed: "kmh", - distance: { 0: "m", 1: "km" }, - temperature: "°F", - ampm: { 0: "", 1: "" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%y/%M/%d", 1: "%y/%m;/%d" }, - abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", - month: "January,February,March,April,May,June,July,August,September,October,November,December", - abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", - day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", - // No translation for english... - }, - "nl_NL": { - lang: "nl_NL", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "\x80", - int_curr_symbol: "EUR", - speed: "kmh", - distance: { 0: "m", 1: "km" }, - temperature: "°C", - ampm: { 0: "", 1: "" }, - timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, - datePattern: { 0: "%A %B %d %Y", 1: "%d.%m.%y" }, // zondag 1 maart 2020 // 01.01.20 - abday: "zo,ma,di,wo,do,vr,za", - day: "zondag,maandag,dinsdag,woensdag,donderdag,vrijdag,zaterdag", - abmonth: "jan,feb,mrt,apr,mei,jun,jul,aug,sep,okt,nov,dec", - month: "januari,februari,maart,april,mei,juni,juli,augustus,september,oktober,november,december", - // No translation for english... - }, - "en_CA": { - lang: "en_CA", - decimal_point: ".", - thousands_sep: ",", - currency_symbol: "$", - int_curr_symbol: "CAD", - speed: "mph", - distance: { 0: "mi", 1: "kmi" }, - temperature: "°F", - ampm: { 0: "am", 1: "pm" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%A, %B %d, %Y", "1": "%Y-%m-%d" }, // Sunday, March 1, 2020 // 2012-12-20 - abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", - month: "January,February,March,April,May,June,July,August,September,October,November,December", - abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", - day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", - // No translation for english... - }, - "fr_FR": { - lang: "fr_FR", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "\x80", - int_curr_symbol: "EUR", - speed: "kmh", - distance: { 0: "m", 1: "km" }, - temperature: "°C", - ampm: { 0: "", 1: "" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%A %d %B %Y", "1": "%d/%m/%Y" }, // dimanche 1 mars 2020 // 01/03/2020 - abmonth: "janv,févr,mars,avril,mai,juin,juil,août,sept,oct,nov,déc", - month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre", - abday: "dim,lun,mar,mer,jeu,ven,sam", - day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi", - trans: { yes: "oui", Yes: "Oui", no: "no", No: "No", ok: "ok", on: "on", off: "off" } - }, - "sv_SE": { - lang: "sv_SE", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "kr", - int_curr_symbol: "SKR", - speed: "kmh", - distance: { 0: "m", 1: "km" }, - temperature: "°C", - ampm: { 0: "fm", 1: "em" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%A %B %d %Y", "1": "%Y-%m-%d" }, // söndag 1 mars 2020 // 2020-03-01 - abmonth: "jan,feb,mars,apr,maj,juni,juli,aug,sep,okt,nov,dec", - month: "januari,februari,mars,april,maj,juni,juli,augusti,september,oktober,november,december", - abday: "sön,mån,tis,ons,tors,fre,lör", - day: "söndag,måndag,tisdag,onsdag,torsdag,fredag,lördag", - trans: { yes: "ja", Yes: "Ja", no: "nej", No: "Nej", ok: "ok", on: "on", off: "off" } - }, - "en_AU": { - lang: "en_AU", - decimal_point: ".", - thousands_sep: ",", - currency_symbol: "$", - int_curr_symbol: "AUD", - speed: "mph", - distance: { 0: "mi", 1: "kmi" }, - temperature: "°F", - ampm: { 0: "am", 1: "pm" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%A, %B %d, %Y", "1": "%m/%d/%y" }, // Sunday, 1 March 2020 // 1/3/20 - abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", - month: "January,February,March,April,May,June,July,August,September,October,November,December", - abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", - day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", - // No translation for english... - }, - "de_AT": { - lang: "de_AT", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "\x80", - int_curr_symbol: "EUR", - speed: "kmh", - distance: { 0: "m", 1: "km" }, - temperature: "°C", - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%y" }, // Sonntag, 1. März 2020 // 01.03.20 - abmonth: "Jän,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez", - month: "Jänner,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember", - abday: "So,Mo,Di,Mi,Do,Fr,Sa", - day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag", - trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" } - }, - "en_IL": { - lang: "en_IL", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "₪", - int_curr_symbol: "ILS", - speed: "kmh", - distance: { 0: "m", 1: "km" }, - temperature: "°C", - ampm: { 0: "am", 1: "pm" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%A, %B %d, %Y", "1": "%d/%m/%Y" }, // Sunday, 1 March 2020 // 01/03/2020 - abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", - month: "January,February,March,April,May,June,July,August,September,October,November,December", - abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", - day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", - // No translation for english... - }, - "es_ES": { - lang: "es_ES", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "\x80", - int_curr_symbol: "EUR", - speed: "kmh", - distance: { 0: "m", 1: "km" }, - temperature: "°C", - ampm: { 0: "", 1: "" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%A, %d de %B de %Y", "1": "%d/%m/%y" }, // domingo, 1 de marzo de 2020 // 01/03/20 - abmonth: "ene,feb,mar,abr,may,jun,jul,ago,sept,oct,nov,dic", - month: "enero,febrero,marzo,abril,mayo,junio,julio,agosto,septiembre,octubre,noviembre,diciembre", - abday: "dom,lun,mar,mié,jue,vie,sáb", - day: "domingo,lunes,martes,miércoles,jueves,viernes,sábado", - trans: { yes: "sí", Yes: "Sí", no: "no", No: "No", ok: "ok", on: "on", off: "off" } - }, - "fr_BE": { - lang: "fr_BE", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "\x80", - int_curr_symbol: "EUR", - speed: "kmh", - distance: { 0: "m", 1: "km" }, - temperature: "°C", - ampm: { 0: "", 1: "" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%y" }, // dimanche 1 mars 2020 // 01/03/20 - abmonth: "anv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.", - month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre", - abday: "dim,lun,mar,mer,jeu,ven,sam", - day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi", - trans: { yes: "oui", Yes: "Oui", no: "no", No: "No", ok: "ok", on: "on", off: "off" } - }, - "fi_FI": { - lang: "fi_FI", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "\x80", - int_curr_symbol: "EUR", - speed: "kmh", - distance: { 0: "m", 1: "km" }, - temperature: "°C", - ampm: { 0: "ap", 1: "ip" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, // 17.00.00 // 17.00 - datePattern: { 0: "%A %d. %B %Y", "1": "%-d/%-m/%Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020 - abmonth: "tammik,helmik,maalisk,huhtik,toukok,kesäk,heinäk,elok,syysk,lokak,marrask,jouluk", - month: "tammikuuta,helmikuuta,maaliskuuta,huhtikuuta,toukokuuta,kesäkuuta,heinäkuuta,elokuuta,syyskuuta,lokakuuta,marraskuuta,joulukuuta", - abday: "su,ma,ti,ke,to,pe,la", - day: "sunnuntaina,maanantaina,tiistaina,keskiviikkona,torstaina,perjantaina,lauantaina", - trans: { yes: "oui", Yes: "Oui", no: "no", No: "No", ok: "ok", on: "on", off: "off" } - }, - "de_CH": { - lang: "de_CH", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "CHF", - int_curr_symbol: "CHF", - speed: "kmh", - distance: { 0: "m", 1: "km" }, - temperature: "°C", - ampm: { 0: "vorm", 1: " nachm" }, - timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, - datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%Y" }, // Sonntag, 1. März 2020 // 1.3.2020 - abmonth: "Jan,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez", - month: "Januar,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember", - abday: "So,Mo,Di,Mi,Do,Fr,Sa", - day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag", - trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" } - }, - "fr_CH": { - lang: "fr_CH", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "CHF", - int_curr_symbol: "CHF", - speed: "kmh", - distance: { 0: "m", 1: "km" }, - temperature: "°C", - ampm: { 0: "AM", 1: "PM" }, - timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, - datePattern: { 0: "%A %d %B %Y", "1": "%d/%m/%y" }, // dimanche 1 mars 2020 // 01/03/20 - abmonth: "anv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.", - month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre", - abday: "dim,lun,mar,mer,jeu,ven,sam", - day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi", - trans: { yes: "oui", Yes: "Oui", no: "no", No: "No", ok: "ok", on: "on", off: "off" } - }, - "it_CH": { - lang: "it_CH", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "CHF", - int_curr_symbol: "CHF", - speed: 'kmh', - distance: { "0": "m", "1": "km" }, - temperature: '°C', - ampm: { 0: "", 1: "" }, - timePattern: { 0: "%HH.%MM.%SS ", 1: "%HH.%MM" }, // 17.00.00 // 17.00 - datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020 - abmonth: "gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic", - month: "gennaio,febbraio,marzo,aprile,maggio,giugno,luglio,agosto,settembre,ottobre,novembre,dicembre", - abday: "dom,lun,mar,mer,gio,ven,sab", - day: "domenica,lunedì,martedì,mercoledì,giovedì,venerdì, sabato", - trans: { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" } - }, - "it_IT": { - lang: "it_IT", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "\x80", - int_curr_symbol: "EUR", - speed: 'kmh', - distance: { "0": "m", "1": "km" }, - temperature: '°C', - ampm: { 0: "", 1: "" }, - timePattern: { 0: "%HH.%MM.%SS ", 1: "%HH.%MM" }, // 17.00.00 // 17.00 - datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020 - abmonth: "gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic", - month: "gennaio,febbraio,marzo,aprile,maggio,giugno,luglio,agosto,settembre,ottobre,novembre,dicembre", - abday: "dom,lun,mar,mer,gio,ven,sab", - day: "domenica,lunedì,martedì,mercoledì,giovedì,venerdì, sabato", - trans: { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" } - }, - "wae_CH": { - lang: "wae_CH", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "CHF", - int_curr_symbol: "CHF", - speed: 'kmh', - distance: { "0": "m", "1": "km" }, - temperature: '°C', - ampm: { 0: "", 1: "" }, - timePattern: { 0: "%HH.%MM.%SS ", 1: "%HH.%MM" }, // 17.00.00 // 17.00 - datePattern: { 0: "%A, %d. %B %Y", "1": "%Y-%m-%d" }, // Sunntag, 1. Märze 2020 // 2020-03-01 - abmonth: "Jen,Hor,Mär,Abr,Mei,Brá,Hei,Öig,Her,Wím,Win,Chr", - month: "Jenner,Hornig,Märze,Abrille,Meije,Bráčet,Heiwet,Öigšte,Herbštmánet,Wímánet,Wintermánet,Chrištmánet", - abday: "Sun,Män,Ziš,Mit,Fró,Fri,Sam", - day: "Sunntag,Mäntag,Zištag,Mittwuč,Fróntag,Fritag,Samštag", - trans: { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" } - }, - "tr_TR": { // this is default - lang: "tr_TR", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "TL", - int_curr_symbol: "TRY", - speed: 'kmh', - distance: { "0": "m", "1": "km" }, - temperature: '°C', - ampm: { 0: "öö", 1: "ös" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%d %w %Y %A", 1: "%d/%m/%Y" }, // 1 Mart 2020 Pazar // "01/03/2020" - abmonth: "Oca,Sub,Mar,Nis,May,Haz,Tem,Agu,Eyl,Eki,Kas,Ara", - month: "Ocak,Subat,Mart,Nisan,Mayis,Haziran,Temmuz,Agustos,Eylul,Ekim,Kasim,Aralik", - abday: "Paz,Pzt,Sal,Car,Per,Cum,Cmt", - day: "Pazar,Pazartesi,Sali,Carsamba,Persembe,Cuma,Cumartesi", - trans: { yes: "evet", Yes: "Evet", no: "hayir", No: "Hayir", ok: "tamam", on: "acik", off: "kapali" } - }, - "hu_HU": { - lang: "hu_HU", - decimal_point: ",", - thousands_sep: " ", - currency_symbol: "Ft", - int_curr_symbol: "HUF", - speed: 'kph', - distance: { "0": "m", "1": "km" }, - temperature: '°C', - ampm: { 0: "de", 1: "du" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%Y %b %d, %A", 1: "%Y.%m.%d" }, // 2020 Feb 28, Péntek" // "2020.03.01."(short) - abmonth: "Jan,Feb,Már,Ápr,Máj,Jún,Júl,Aug,Szep,Okt,Nov,Dec", - month: "Január,Február,Március,Április,Május,Június,Július,Augusztus,Szeptember,Október,November,December", - abday: "Vas,Hét,Ke,Szer,Csüt,Pén,Szom", - day: "Vasárnap,Hétfő,Kedd,Szerda,Csütörtök,Péntek,Szombat", - trans: { yes: "igen", Yes: "Igen", no: "nem", No: "Nem", ok: "ok", on: "be", off: "ki" } - }, - "pt_BR": { - lang: "pt_BR", - decimal_point: ",", - thousands_sep: ".", - currency_symbol: "R$", currency_first: true, - int_curr_symbol: "BRL", - speed: "kmh", - distance: { 0: "m", 1: "km" }, - temperature: "°C", - ampm: { 0: "am", 1: "pm" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "", 1: "%d/%m/%y" }, - abmonth: "Jan,Fev,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez", - month: "Janeiro,Fevereiro,Março,Abril,Maio,Junho,Julho,Agosto,Setembro,Outubro,Novembro,Dezembro", - abday: "Dom,Seg,Ter,Qua,Qui,Sex,Sab", - day: "Domingo,Segunda-feira,Terça-feira,Quarta-feira,Quinta-feira,Sexta-feira,Sábado", - trans: { yes: "sim", Yes: "Sim", no: "não", No: "Não", ok: "certo", on: "ligado", off: "desligado" } - }, - "cs_CZ": { - lang: "cs_CZ", - decimal_point: ",", - thousands_sep: " ", - currency_symbol: "Kč", - int_curr_symbol: " CZK", - speed: 'kmh', - distance: { "0": "m", "1": "km" }, - temperature: '°C', - ampm: { 0: "dop", 1: "odp" }, - timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%d. %b %Y", 1: "%d.%m.%Y" }, // "30. led 2020" // "30.01.2020"(short) - abmonth: "led,úno,bře,dub,kvě,čvn,čvc,srp,zář,říj,lis,pro", - month: "leden,únor,březen,duben,květen,červen,červenec,srpen,září,říjen,listopad,prosinec", - abday: "ne,po,út,st,čt,pá,so", - day: "neděle,pondělí,úterý,středa,čtvrtek,pátek,sobota", - trans: { yes: "tak", Yes: "Tak", no: "nie", No: "Nie", ok: "ok", on: "na", off: "poza" } - } + "en_GB": { // this is default + lang: "en_GB", + decimal_point: ".", + thousands_sep: ",", + currency_symbol: "£", currency_first: true, + int_curr_symbol: "GBP", + speed: 'mph', + distance: { "0": "yd", "1": "mi" }, + temperature: '°C', + ampm: { 0: "am", 1: "pm" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%b %d %Y", 1: "%d/%m/%Y" }, // Feb 28 2020" // "01/03/2020"(short) + abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", + month: "January,February,March,April,May,June,July,August,September,October,November,December", + abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", + day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", + // No translation for english... + }, + "en_IN": { + lang: "en_IN", + decimal_point: ".", + thousands_sep: ",", + currency_symbol: "Rs.", + currency_first: true, + int_curr_symbol: "INR", + speed: 'kms', + distance: { "0": "m", "1": "km" }, + temperature: '°C', + ampm: { 0: "am", 1: "pm" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%d %b %Y", 1: "%d/%m/%Y" }, // 28 Feb 2020" // "28/03/2020"(short) + abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", + month: "January,February,March,April,May,June,July,August,September,October,November,December", + abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", + day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", + // No translation for english... + }, + "de_DE": { + lang: "de_DE", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "€", + int_curr_symbol: "EUR", + speed: "kmh", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + ampm: { 0: "", 1: "" }, + timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, + datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%Y" }, // Sonntag, 1. März 2020 // 01.01.20 + abmonth: "Jan,Feb,Mär,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez", + month: "Januar,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember", + abday: "So,Mo,Di,Mi,Do,Fr,Sa", + day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag", + trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus", "< Back": "< Zurück" } + }, + "en_US": { + lang: "en_US", + decimal_point: ".", + thousands_sep: ",", + currency_symbol: "$", currency_first: true, + int_curr_symbol: "USD", + speed: "mph", + distance: { 0: "yd", 1: "mi" }, + temperature: "°F", + ampm: { 0: "am", 1: "pm" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%b %d, %Y", 1: "%m/%d/%y" }, + abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", + month: "January,February,March,April,May,June,July,August,September,October,November,December", + abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", + day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", + // No translation for english... + }, + "en_JP": { // we do not have the font, so it is not ja_JP + lang: "en_JP", + decimal_point: ".", + thousands_sep: ",", + currency_symbol: "¥", + int_curr_symbol: "JPY", + speed: "kmh", + distance: { 0: "m", 1: "km" }, + temperature: "°F", + ampm: { 0: "", 1: "" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%y/%M/%d", 1: "%y/%m;/%d" }, + abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", + month: "January,February,March,April,May,June,July,August,September,October,November,December", + abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", + day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", + // No translation for english... + }, + "nl_NL": { + lang: "nl_NL", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "€", + int_curr_symbol: "EUR", + speed: "kmh", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + ampm: { 0: "", 1: "" }, + timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, + datePattern: { 0: "%A %B %d %Y", 1: "%d.%m.%y" }, // zondag 1 maart 2020 // 01.01.20 + abday: "zo,ma,di,wo,do,vr,za", + day: "zondag,maandag,dinsdag,woensdag,donderdag,vrijdag,zaterdag", + abmonth: "jan,feb,mrt,apr,mei,jun,jul,aug,sep,okt,nov,dec", + month: "januari,februari,maart,april,mei,juni,juli,augustus,september,oktober,november,december", + // No translation for english... + }, + "en_CA": { + lang: "en_CA", + decimal_point: ".", + thousands_sep: ",", + currency_symbol: "$", + int_curr_symbol: "CAD", + speed: "km/h", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + ampm: { 0: "am", 1: "pm" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%A, %B %d, %Y", "1": "%Y-%m-%d" }, // Sunday, March 1, 2020 // 2012-12-20 + abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", + month: "January,February,March,April,May,June,July,August,September,October,November,December", + abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", + day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", + // No translation for english... + }, + "fr_FR": { + lang: "fr_FR", + decimal_point: ",", + thousands_sep: " ", + currency_symbol: "€", + int_curr_symbol: "EUR", + speed: "km/h", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + ampm: { 0: "", 1: "" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%A %d %B %Y", "1": "%d/%m/%Y" }, // dimanche 1 mars 2020 // 01/03/2020 + abmonth: "janv,févr,mars,avril,mai,juin,juil,août,sept,oct,nov,déc", + month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre", + abday: "dim,lun,mar,mer,jeu,ven,sam", + day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi", + trans: { yes: "oui", Yes: "Oui", no: "non", No: "Non", ok: "ok", on: "on", off: "off" } + }, + "sv_SE": { + lang: "sv_SE", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "kr", + int_curr_symbol: "SKR", + speed: "kmh", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + ampm: { 0: "fm", 1: "em" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%A %B %d %Y", "1": "%Y-%m-%d" }, // söndag 1 mars 2020 // 2020-03-01 + abmonth: "jan,feb,mars,apr,maj,juni,juli,aug,sep,okt,nov,dec", + month: "januari,februari,mars,april,maj,juni,juli,augusti,september,oktober,november,december", + abday: "sön,mån,tis,ons,tors,fre,lör", + day: "söndag,måndag,tisdag,onsdag,torsdag,fredag,lördag", + trans: { yes: "ja", Yes: "Ja", no: "nej", No: "Nej", ok: "ok", on: "on", off: "off" } + }, + "en_AU": { + lang: "en_AU", + decimal_point: ".", + thousands_sep: ",", + currency_symbol: "$", + int_curr_symbol: "AUD", + speed: "kmh", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + ampm: { 0: "am", 1: "pm" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%A, %B %d, %Y", "1": "%d/%m/%y" }, // Sunday, 1 March 2020 // 1/3/20 + abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", + month: "January,February,March,April,May,June,July,August,September,October,November,December", + abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", + day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", + // No translation for english... + }, + "de_AT": { + lang: "de_AT", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "€", + int_curr_symbol: "EUR", + speed: "kmh", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%y" }, // Sonntag, 1. März 2020 // 01.03.20 + abmonth: "Jän,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez", + month: "Jänner,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember", + abday: "So,Mo,Di,Mi,Do,Fr,Sa", + day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag", + trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" } + }, + "en_IL": { + lang: "en_IL", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "ILS"/*"₪"*/, + int_curr_symbol: "ILS", + speed: "kmh", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + ampm: { 0: "am", 1: "pm" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%A, %B %d, %Y", "1": "%d/%m/%Y" }, // Sunday, 1 March 2020 // 01/03/2020 + abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", + month: "January,February,March,April,May,June,July,August,September,October,November,December", + abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", + day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", + // No translation for english... + }, + "es_ES": { + lang: "es_ES", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "€", + int_curr_symbol: "EUR", + speed: "kmh", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + ampm: { 0: "", 1: "" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%A, %d de %B de %Y", "1": "%d/%m/%y" }, // domingo, 1 de marzo de 2020 // 01/03/20 + abmonth: "ene,feb,mar,abr,may,jun,jul,ago,sept,oct,nov,dic", + month: "enero,febrero,marzo,abril,mayo,junio,julio,agosto,septiembre,octubre,noviembre,diciembre", + abday: "dom,lun,mar,mié,jue,vie,sáb", + day: "domingo,lunes,martes,miércoles,jueves,viernes,sábado", + trans: { yes: "sí", Yes: "Sí", no: "no", No: "No", ok: "ok", on: "on", off: "off" } + }, + "fr_BE": { + lang: "fr_BE", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "€", + int_curr_symbol: "EUR", + speed: "kmh", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + ampm: { 0: "", 1: "" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%y" }, // dimanche 1 mars 2020 // 01/03/20 + abmonth: "anv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.", + month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre", + abday: "dim,lun,mar,mer,jeu,ven,sam", + day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi", + trans: { yes: "oui", Yes: "Oui", no: "non", No: "Non", ok: "ok", on: "on", off: "off" } + }, + "fi_FI": { + lang: "fi_FI", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "€", + int_curr_symbol: "EUR", + speed: "kmh", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + ampm: { 0: "ap", 1: "ip" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, // 17.00.00 // 17.00 + datePattern: { 0: "%A %d. %B %Y", "1": "%-d/%-m/%Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020 + abmonth: "tammik,helmik,maalisk,huhtik,toukok,kesäk,heinäk,elok,syysk,lokak,marrask,jouluk", + month: "tammikuuta,helmikuuta,maaliskuuta,huhtikuuta,toukokuuta,kesäkuuta,heinäkuuta,elokuuta,syyskuuta,lokakuuta,marraskuuta,joulukuuta", + abday: "su,ma,ti,ke,to,pe,la", + day: "sunnuntaina,maanantaina,tiistaina,keskiviikkona,torstaina,perjantaina,lauantaina", + trans: { yes: "oui", Yes: "Oui", no: "no", No: "No", ok: "ok", on: "on", off: "off" } + }, + "de_CH": { + lang: "de_CH", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "CHF", + int_curr_symbol: "CHF", + speed: "kmh", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + ampm: { 0: "vorm", 1: " nachm" }, + timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, + datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%Y" }, // Sonntag, 1. März 2020 // 1.3.2020 + abmonth: "Jan,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez", + month: "Januar,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember", + abday: "So,Mo,Di,Mi,Do,Fr,Sa", + day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag", + trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" } + }, + "fr_CH": { + lang: "fr_CH", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "CHF", + int_curr_symbol: "CHF", + speed: "kmh", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + ampm: { 0: "AM", 1: "PM" }, + timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, + datePattern: { 0: "%A %d %B %Y", "1": "%d/%m/%y" }, // dimanche 1 mars 2020 // 01/03/20 + abmonth: "anv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.", + month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre", + abday: "dim,lun,mar,mer,jeu,ven,sam", + day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi", + trans: { yes: "oui", Yes: "Oui", no: "non", No: "Non", ok: "ok", on: "on", off: "off" } + }, + "it_CH": { + lang: "it_CH", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "CHF", + int_curr_symbol: "CHF", + speed: 'kmh', + distance: { "0": "m", "1": "km" }, + temperature: '°C', + ampm: { 0: "", 1: "" }, + timePattern: { 0: "%HH.%MM.%SS ", 1: "%HH.%MM" }, // 17.00.00 // 17.00 + datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020 + abmonth: "gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic", + month: "gennaio,febbraio,marzo,aprile,maggio,giugno,luglio,agosto,settembre,ottobre,novembre,dicembre", + abday: "dom,lun,mar,mer,gio,ven,sab", + day: "domenica,lunedì,martedì,mercoledì,giovedì,venerdì, sabato", + trans: { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" } + }, + "it_IT": { + lang: "it_IT", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "€", + int_curr_symbol: "EUR", + speed: 'kmh', + distance: { "0": "m", "1": "km" }, + temperature: '°C', + ampm: { 0: "", 1: "" }, + timePattern: { 0: "%HH.%MM.%SS ", 1: "%HH.%MM" }, // 17.00.00 // 17.00 + datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020 + abmonth: "gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic", + month: "gennaio,febbraio,marzo,aprile,maggio,giugno,luglio,agosto,settembre,ottobre,novembre,dicembre", + abday: "dom,lun,mar,mer,gio,ven,sab", + day: "domenica,lunedì,martedì,mercoledì,giovedì,venerdì, sabato", + trans: { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" } + }, + "wae_CH": { + lang: "wae_CH", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "CHF", + int_curr_symbol: "CHF", + speed: 'kmh', + distance: { "0": "m", "1": "km" }, + temperature: '°C', + ampm: { 0: "", 1: "" }, + timePattern: { 0: "%HH.%MM.%SS ", 1: "%HH.%MM" }, // 17.00.00 // 17.00 + datePattern: { 0: "%A, %d. %B %Y", "1": "%Y-%m-%d" }, // Sunntag, 1. Märze 2020 // 2020-03-01 + abmonth: "Jen,Hor,Mär,Abr,Mei,Brá,Hei,Öig,Her,Wím,Win,Chr", + month: "Jenner,Hornig,Märze,Abrille,Meije,Bráčet,Heiwet,Öigšte,Herbštmánet,Wímánet,Wintermánet,Chrištmánet", + abday: "Sun,Män,Ziš,Mit,Fró,Fri,Sam", + day: "Sunntag,Mäntag,Zištag,Mittwuč,Fróntag,Fritag,Samštag", + trans: { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" } + }, + "tr_TR": { // this is default + lang: "tr_TR", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "TL", + int_curr_symbol: "TRY", + speed: 'kmh', + distance: { "0": "m", "1": "km" }, + temperature: '°C', + ampm: { 0: "öö", 1: "ös" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%d %w %Y %A", 1: "%d/%m/%Y" }, // 1 Mart 2020 Pazar // "01/03/2020" + abmonth: "Oca,Sub,Mar,Nis,May,Haz,Tem,Agu,Eyl,Eki,Kas,Ara", + month: "Ocak,Subat,Mart,Nisan,Mayis,Haziran,Temmuz,Agustos,Eylul,Ekim,Kasim,Aralik", + abday: "Paz,Pzt,Sal,Car,Per,Cum,Cmt", + day: "Pazar,Pazartesi,Sali,Carsamba,Persembe,Cuma,Cumartesi", + trans: { yes: "evet", Yes: "Evet", no: "hayir", No: "Hayir", ok: "tamam", on: "acik", off: "kapali" } + }, + "hu_HU": { + lang: "hu_HU", + decimal_point: ",", + thousands_sep: " ", + currency_symbol: "Ft", + int_curr_symbol: "HUF", + speed: 'kph', + distance: { "0": "m", "1": "km" }, + temperature: '°C', + ampm: { 0: "de", 1: "du" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%Y %b %d, %A", 1: "%Y.%m.%d" }, // 2020 Feb 28, Péntek" // "2020.03.01."(short) + abmonth: "Jan,Feb,Már,Ápr,Máj,Jún,Júl,Aug,Szep,Okt,Nov,Dec", + month: "Január,Február,Március,Április,Május,Június,Július,Augusztus,Szeptember,Október,November,December", + abday: "Vas,Hét,Ke,Szer,Csüt,Pén,Szom", + day: "Vasárnap,Hétfő,Kedd,Szerda,Csütörtök,Péntek,Szombat", + trans: { yes: "igen", Yes: "Igen", no: "nem", No: "Nem", ok: "ok", on: "be", off: "ki" } + }, + "pt_BR": { + lang: "pt_BR", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "R$", currency_first: true, + int_curr_symbol: "BRL", + speed: "kmh", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + ampm: { 0: "am", 1: "pm" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%d %b %Y", 1: "%d/%m/%y" }, + abmonth: "Jan,Fev,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez", + month: "Janeiro,Fevereiro,Março,Abril,Maio,Junho,Julho,Agosto,Setembro,Outubro,Novembro,Dezembro", + abday: "Dom,Seg,Ter,Qua,Qui,Sex,Sab", + day: "Domingo,Segunda-feira,Terça-feira,Quarta-feira,Quinta-feira,Sexta-feira,Sábado", + trans: { yes: "sim", Yes: "Sim", no: "não", No: "Não", ok: "certo", on: "ligado", off: "desligado" } + }, + "cs_CZ": { // THIS NEVER WORKED PROPERLY - many chars are not in the ISO8859-1 codepage and we use charFallbacks + lang: "cs_CZ", + decimal_point: ",", + thousands_sep: " ", + currency_symbol: "Kč", + int_curr_symbol: " CZK", + speed: 'kmh', + distance: { "0": "m", "1": "km" }, + temperature: '°C', + ampm: { 0: "dop", 1: "odp" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%d. %b %Y", 1: "%d.%m.%Y" }, // "30. led 2020" // "30.01.2020"(short) + abmonth: "led,úno,bře,dub,kvě,čvn,čvc,srp,zář,říj,lis,pro", + month: "leden,únor,březen,duben,květen,červen,červenec,srpen,září,říjen,listopad,prosinec", + abday: "ne,po,út,st,čt,pá,so", + day: "neděle,pondělí,úterý,středa,čtvrtek,pátek,sobota", + trans: { yes: "tak", Yes: "Tak", no: "nie", No: "Nie", ok: "ok", on: "na", off: "poza" } + }, + "sl_SI": { + lang: "sl_SI", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "€", + int_curr_symbol: "EUR", + speed: "km/h", + distance: { 0: "m", 1: "km" }, + temperature: "°C", + ampm: { 0: "dop.", 1: "pop." }, + timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, + datePattern: { 0: "%-d. %b %Y", 1: "%-d.%-m.%Y" }, // "3. jan. 2020" // "3.1.2020"(short) + abmonth: "jan.,feb.,mar.,apr.,maj,jun.,jul.,avg.,sep.,okt.,nov.,dec.", + month: "januar,februar,marec,april,maj,junij,julij,avgust,september,oktober,november,december", + abday: "ned.,pon.,tor.,sre.,čet.,pet.,sob.", + day: "nedelja,ponedeljek,torek,sreda,četrtek,petek,sobota", + trans: { yes: "da", Yes: "Da", no: "ne", No: "Ne", ok: "ok", on: "Vklj.", off: "Izklj.", "< Back": "< Nazaj" } + }/*, + "he_IL": { // This won't work until we get a font - see https://github.com/espruino/BangleApps/issues/399 + codePage : "ISO8859-8", + lang: "he_IL", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "₪", + int_curr_symbol: "ILS", + speed: "קמ״ש", + distance: { 0: "מ׳", 1: "ק״מ" }, + temperature: "°C", + ampm: {0:"am",1:"pm"}, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%A, %B %d, %Y", "1": "%d/%m/%Y" }, // Sunday, 1 March 2020 // 01/03/2020 + abmonth: "ינו,פבר,מרץ,אפר,מאי,יונ,יול,אוג,ספט,אוק,נוב,דצמ", + month: "ינואר,פברואר,מרץ,אפריל,מאי,יוני,יולי,אוגוסט,ספטמבר,אוקטובר,נובמבר,דצמבר", + abday: "א׳,ב׳,ג׳,ד׳,ה,ו׳,ש׳", + day: "ראשון,שני,שלישי,רביעי,חמישי,שישי,שבת", + trans: { yes: "כן", Yes: "כן", no: "לא", No: "לא", ok: "אישור", on: "פעיל", off: "כבוי" } + }*/ }; diff --git a/apps/magnav/ChangeLog b/apps/magnav/ChangeLog new file mode 100644 index 000000000..6a33b0ce9 --- /dev/null +++ b/apps/magnav/ChangeLog @@ -0,0 +1,4 @@ +0.01: New App! +0.02: Course marker +0.03: Tilt compensation and calibration + diff --git a/apps/magnav/README.md b/apps/magnav/README.md new file mode 100644 index 000000000..a036644fb --- /dev/null +++ b/apps/magnav/README.md @@ -0,0 +1,26 @@ +# Navigation Compass + +This is a tilt and roll compensated compass with a linear display. The compass will display the same direction that it shows when flat as when it is tilted (rotation around the W-S axis) or rolled (rotation around the N-S) axis. *Even with compensation, it would be beyond foolish to rely solely on this app for any serious navigational purpose.* + +![](screenshot.jpg) + +## Calibration + +Correct operation of this app depends critically on calibration. When first run on a Bangle, the app will request calibration. This lasts for 30 seconds during which you should move the watch slowly through figures of 8. It is important that during calibration the watch is fully rotated around each of it axes. If the app does give the correct direction heading or is not stable with respect to tilt and roll - redo the calibration by pressing *BTN3*. Calibration data is recorded in a storage file named `magnav.json`. + +## Controls + +*BTN1* - switches to your selected clock app. + +*BTN2* - switches to the app launcher. + +*BTN3* - invokes calibration ( can be cancelled if pressed accidentally) + +*Touch Left* - marks the current heading with a blue circle - see screen shot. This can be used to take a bearing and then follow it. + +*Touch Right* - cancels the marker (blue circle not displayed). + + +## Support + +Please report bugs etc. by raising an issue [here](https://github.com/jeffmer/JeffsBangleAppsDev). \ No newline at end of file diff --git a/apps/magnav/magnav-icon.js b/apps/magnav/magnav-icon.js new file mode 100644 index 000000000..efdad48f9 --- /dev/null +++ b/apps/magnav/magnav-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/ACMBiIACiAWQCoYADCyEimf/mczkQYOBwMj/4ABC4MzmQYMLYMvCwQXDDARjKFogXFDAQuJiQWEC4szkIwIIooXHGBAuHC4wwIFwXcp4XKGA8Rn//7vMAYIXImYXFIwc97nNDAQXHJAsBj4RB/owBDAQXHmIXERofz7vcDAQXHMApeCAAPdGAIYBC45gFUok9GAXM4hgIXpBgBGAQYIPAcBibTEC4IwC4fzPBIXGJAk/C5amCJAnM74VBVQwXKVIPMbAQXRMAIXEJAoXLnpdDC5Z3FMAPTB4LhCC6ApEC5bXEDAwwBDwjvDgAXHCQgwFC4kRKoQAFGAgXDiIXEl4XKSIkyC4ioHC4qsCOwh4KRYoFCkIXEMBIXEn5eGMBQXGLwpIKC4hGIGBIWFFw4wJFxwwCkYXJFxIwCJIoWFFxIwCGIgWEFxQYEkTRDkQWODAYAFCxxjDAARbLAH4AFA==")) diff --git a/apps/magnav/magnav.js b/apps/magnav/magnav.js new file mode 100644 index 000000000..111d42c38 --- /dev/null +++ b/apps/magnav/magnav.js @@ -0,0 +1,220 @@ + +const Yoff = 80; +var pal2color = new Uint16Array([0x0000,0xffff,0x07ff,0xC618],0,2); +var buf = Graphics.createArrayBuffer(240,50,2,{msb:true}); +Bangle.setLCDTimeout(30); + +function flip(b,y) { + g.drawImage({width:240,height:50,bpp:2,buffer:b.buffer, palette:pal2color},0,y); + b.clear(); +} + +const labels = ["N","NE","E","SE","S","SW","W","NW"]; +var brg=null; + +function drawCompass(course) { + buf.setColor(1); + buf.setFont("Vector",16); + var start = course-90; + if (start<0) start+=360; + buf.fillRect(28,45,212,49); + var xpos = 30; + var frag = 15 - start%15; + if (frag<15) xpos+=frag; else frag = 0; + for (var i=frag;i<=180-frag;i+=15){ + var res = start + i; + if (res%90==0) { + buf.drawString(labels[Math.floor(res/45)%8],xpos-8,0); + buf.fillRect(xpos-2,25,xpos+2,45); + } else if (res%45==0) { + buf.drawString(labels[Math.floor(res/45)%8],xpos-12,0); + buf.fillRect(xpos-2,30,xpos+2,45); + } else if (res%15==0) { + buf.fillRect(xpos,35,xpos+1,45); + } + xpos+=15; + } + if (brg) { + var bpos = brg - course; + if (bpos>180) bpos -=360; + if (bpos<-180) bpos +=360; + bpos+=120; + if (bpos<30) bpos = 14; + if (bpos>210) bpos = 226; + buf.setColor(2); + buf.fillCircle(bpos,40,8); + } + flip(buf,Yoff); +} + +var heading = 0; +function newHeading(m,h){ + var s = Math.abs(m - h); + var delta = (m>h)?1:-1; + if (s>=180){s=360-s; delta = -delta;} + if (s<2) return h; + var hd = h + delta*(1 + Math.round(s/5)); + if (hd<0) hd+=360; + if (hd>360)hd-= 360; + return hd; +} + +var candraw = false; +var CALIBDATA = require("Storage").readJSON("magnav.json",1)||null; + +function tiltfixread(O,S){ + var start = Date.now(); + var m = Bangle.getCompass(); + var g = Bangle.getAccel(); + m.dx =(m.x-O.x)*S.x; m.dy=(m.y-O.y)*S.y; m.dz=(m.z-O.z)*S.z; + var d = Math.atan2(-m.dx,m.dy)*180/Math.PI; + if (d<0) d+=360; + var phi = Math.atan(-g.x/-g.z); + var cosphi = Math.cos(phi), sinphi = Math.sin(phi); + var theta = Math.atan(-g.y/(-g.x*sinphi-g.z*cosphi)); + var costheta = Math.cos(theta), sintheta = Math.sin(theta); + var xh = m.dy*costheta + m.dx*sinphi*sintheta + m.dz*cosphi*sintheta; + var yh = m.dz*sinphi - m.dx*cosphi; + var psi = Math.atan2(yh,xh)*180/Math.PI; + if (psi<0) psi+=360; + return psi; +} + +// Note actual mag is 360-m, error in firmware +function reading() { + var d = tiltfixread(CALIBDATA.offset,CALIBDATA.scale); + heading = newHeading(d,heading); + drawCompass(heading); + buf.setColor(1); + buf.setFont("6x8",2); + buf.setFontAlign(-1,-1); + buf.drawString("o",170,0); + buf.setFont("Vector",40); + var course = Math.round(heading); + var cs = course.toString(); + cs = course<10?"00"+cs : course<100 ?"0"+cs : cs; + buf.drawString(cs,70,10); + flip(buf,Yoff+80); +} + +function calibrate(){ + var max={x:-32000, y:-32000, z:-32000}, + min={x:32000, y:32000, z:32000}; + var ref = setInterval(()=>{ + var m = Bangle.getCompass(); + max.x = m.x>max.x?m.x:max.x; + max.y = m.y>max.y?m.y:max.y; + max.z = m.z>max.z?m.z:max.z; + min.x = m.x<min.x?m.x:min.x; + min.y = m.y<min.y?m.y:min.y; + min.z = m.z<min.z?m.z:min.z; + }, 100); + return new Promise((resolve) => { + setTimeout(()=>{ + if(ref) clearInterval(ref); + var offset = {x:(max.x+min.x)/2,y:(max.y+min.y)/2,z:(max.z+min.z)/2}; + var delta = {x:(max.x-min.x)/2,y:(max.y-min.y)/2,z:(max.z-min.z)/2}; + var avg = (delta.x+delta.y+delta.z)/3; + var scale = {x:avg/delta.x, y:avg/delta.y, z:avg/delta.z}; + resolve({offset:offset,scale:scale}); + },30000); + }); +} + +function docalibrate(e,first){ + const title = "Calibrate"; + const msg = "takes 30 seconds"; + function action(b){ + if (b) { + buf.setColor(1); + buf.setFont("Vector",24); + buf.setFontAlign(0,-1); + buf.drawString("Fig 8s to",120,0); + buf.drawString("Calibrate",120,26); + flip(buf,Yoff); + calibrate().then((r)=>{ + require("Storage").write("magnav.json",r); + CALIBDATA = r; + startdraw(); + setButtons(); + }); + } else { + startdraw(); + setTimeout(setButtons,1000); + } + } + if (first===undefined) first=false; + stopdraw(); + clearWatch(); + if (first) + E.showAlert(msg,title).then(action.bind(null,true)); + else + E.showPrompt(msg,{title:title,buttons:{"Start":true,"Cancel":false}}).then(action); +} + +Bangle.on('touch', function(b) { + if(!candraw) return; + if(b==1) brg=heading; + if(b==2) brg=null; + }); + +var intervalRef; + +function startdraw(){ + g.clear(); + g.setColor(1,0.5,0.5); + g.fillPoly([120,Yoff+50,110,Yoff+70,130,Yoff+70]); + g.setColor(1,1,1); + Bangle.drawWidgets(); + candraw = true; + intervalRef = setInterval(reading,200); +} + +function stopdraw() { + candraw=false; + if(intervalRef) {clearInterval(intervalRef);} +} + +function setButtons(){ + setWatch(()=>{load();}, BTN1, {repeat:false,edge:"falling"}); + setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); + setWatch(docalibrate, BTN3, {repeat:false,edge:"falling"}); +} + +var SCREENACCESS = { + withApp:true, + request:function(){ + this.withApp=false; + stopdraw(); + clearWatch(); + }, + release:function(){ + this.withApp=true; + startdraw(); + setButtons(); + } +}; + +Bangle.on('lcdPower',function(on) { + if (!SCREENACCESS.withApp) return; + if (on) { + startdraw(); + } else { + stopdraw(); + } +}); + +Bangle.on('kill',()=>{Bangle.setCompassPower(0);}); + +Bangle.loadWidgets(); +Bangle.setCompassPower(1); +if (!CALIBDATA) + docalibrate({},true); +else { + startdraw(); + setButtons(); +} + + + + diff --git a/apps/magnav/magnav.min.js b/apps/magnav/magnav.min.js new file mode 100644 index 000000000..03700df14 --- /dev/null +++ b/apps/magnav/magnav.min.js @@ -0,0 +1,10 @@ +var Yoff=80,pal2color=new Uint16Array([0,65535,2047,50712],0,2),buf=Graphics.createArrayBuffer(240,50,2,{msb:!0});Bangle.setLCDTimeout(30);function flip(b,c){g.drawImage({width:240,height:50,bpp:2,buffer:b.buffer,palette:pal2color},0,c);b.clear()}var labels="N NE E SE S SW W NW".split(" "),brg=null; +function drawCompass(b){buf.setColor(1);buf.setFont("Vector",16);var c=b-90;0>c&&(c+=360);buf.fillRect(28,45,212,49);var a=30,d=15-c%15;15>d?a+=d:d=0;for(var e=d;e<=180-d;e+=15){var f=c+e;0==f%90?(buf.drawString(labels[Math.floor(f/45)%8],a-8,0),buf.fillRect(a-2,25,a+2,45)):0==f%45?(buf.drawString(labels[Math.floor(f/45)%8],a-12,0),buf.fillRect(a-2,30,a+2,45)):0==f%15&&buf.fillRect(a,35,a+1,45);a+=15}brg&&(b=brg-b,180<b&&(b-=360),-180>b&&(b+=360),b+=120,30>b&&(b=14),210<b&&(b=226),buf.setColor(2), +buf.fillCircle(b,40,8));flip(buf,Yoff)}var heading=0;function newHeading(b,c){var a=Math.abs(b-c),d=b>c?1:-1;180<=a&&(a=360-a,d=-d);if(2>a)return c;a=c+d*(1+Math.round(a/5));0>a&&(a+=360);360<a&&(a-=360);return a}var candraw=!1,CALIBDATA=require("Storage").readJSON("magnav.json",1)||null; +function tiltfixread(b,c){Date.now();var a=Bangle.getCompass(),d=Bangle.getAccel();a.dx=(a.x-b.x)*c.x;a.dy=(a.y-b.y)*c.y;a.dz=(a.z-b.z)*c.z;var e=Math.atan(-d.x/-d.z),f=Math.cos(e);e=Math.sin(e);d=Math.atan(-d.y/(-d.x*e-d.z*f));var k=Math.sin(d);a=180*Math.atan2(a.dz*e-a.dx*f,a.dy*Math.cos(d)+a.dx*e*k+a.dz*f*k)/Math.PI;0>a&&(a+=360);return a} +function reading(){var b=tiltfixread(CALIBDATA.offset,CALIBDATA.scale);heading=newHeading(b,heading);drawCompass(heading);buf.setColor(1);buf.setFont("6x8",2);buf.setFontAlign(-1,-1);buf.drawString("o",170,0);buf.setFont("Vector",40);b=Math.round(heading);var c=b.toString();buf.drawString(10>b?"00"+c:100>b?"0"+c:c,70,10);flip(buf,Yoff+80)} +function calibrate(){var b=-32E3,c=-32E3,a=-32E3,d=32E3,e=32E3,f=32E3,k=setInterval(function(){var h=Bangle.getCompass();b=h.x>b?h.x:b;c=h.y>c?h.y:c;a=h.z>a?h.z:a;d=h.x<d?h.x:d;e=h.y<e?h.y:e;f=h.z<f?h.z:f},100);return new Promise(function(h){setTimeout(function(){k&&clearInterval(k);var m=(b-d)/2,n=(c-e)/2,p=(a-f)/2,l=(m+n+p)/3;h({offset:{x:(b+d)/2,y:(c+e)/2,z:(a+f)/2},scale:{x:l/m,y:l/n,z:l/p}})},3E4)})} +function docalibrate(b,c){function a(a){a?(buf.setColor(1),buf.setFont("Vector",24),buf.setFontAlign(0,-1),buf.drawString("Fig 8s to",120,0),buf.drawString("Calibrate",120,26),flip(buf,Yoff),calibrate().then(function(a){require("Storage").write("magnav.json",a);CALIBDATA=a;startdraw();setButtons()})):(startdraw(),setTimeout(setButtons,1E3))}void 0===c&&(c=!1);stopdraw();clearWatch();c?E.showAlert("takes 30 seconds","Calibrate").then(a.bind(null,!0)):E.showPrompt("takes 30 seconds",{title:"Calibrate", +buttons:{Start:!0,Cancel:!1}}).then(a)}Bangle.on("touch",function(b){candraw&&(1==b&&(brg=heading),2==b&&(brg=null))});var intervalRef;function startdraw(){g.clear();g.setColor(1,.5,.5);g.fillPoly([120,Yoff+50,110,Yoff+70,130,Yoff+70]);g.setColor(1,1,1);Bangle.drawWidgets();candraw=!0;intervalRef=setInterval(reading,200)}function stopdraw(){candraw=!1;intervalRef&&clearInterval(intervalRef)} +function setButtons(){setWatch(function(){load()},BTN1,{repeat:!1,edge:"falling"});setWatch(Bangle.showLauncher,BTN2,{repeat:!1,edge:"falling"});setWatch(docalibrate,BTN3,{repeat:!1,edge:"falling"})}var SCREENACCESS={withApp:!0,request:function(){this.withApp=!1;stopdraw();clearWatch()},release:function(){this.withApp=!0;startdraw();setButtons()}};Bangle.on("lcdPower",function(b){SCREENACCESS.withApp&&(b?startdraw():stopdraw())});Bangle.on("kill",function(){Bangle.setCompassPower(0)});Bangle.loadWidgets(); +Bangle.setCompassPower(1);CALIBDATA?(startdraw(),setButtons()):docalibrate({},!0); diff --git a/apps/magnav/magnav.png b/apps/magnav/magnav.png new file mode 100644 index 000000000..a395801da Binary files /dev/null and b/apps/magnav/magnav.png differ diff --git a/apps/magnav/screenshot.jpg b/apps/magnav/screenshot.jpg new file mode 100644 index 000000000..0f04b586a Binary files /dev/null and b/apps/magnav/screenshot.jpg differ diff --git a/apps/marioclock/ChangeLog b/apps/marioclock/ChangeLog index 69a3ccc7b..66e4ab800 100644 --- a/apps/marioclock/ChangeLog +++ b/apps/marioclock/ChangeLog @@ -9,4 +9,6 @@ 0.09: Add GadgetBridge functionality. Mario shows message type in speach bubble, while message scrolls in info panel 0.10: Swiping left to enable night-mode now also reduces LCD brightness through 3 levels before returning to day-mode. 0.11: User settings persisted and read to file. -0.12: Add info banner message when phone (dis)connects. Display low-battery warning (<=10%) \ No newline at end of file +0.12: Add info banner message when phone (dis)connects. Display low-battery warning (<=10%) +0.13: Fix drawPyramid function so pyramids are drawn in correct Y position +0.14: Add jumping frame for characters diff --git a/apps/marioclock/marioclock-app.js b/apps/marioclock/marioclock-app.js index 7601b89ba..20d1dfd85 100644 --- a/apps/marioclock/marioclock-app.js +++ b/apps/marioclock/marioclock-app.js @@ -96,30 +96,30 @@ function phoneOutbound(msg) { } function phoneClearMessage() { - if (phone.message === null) return; + if (phone.message === null) return; - if (phone.messageTimeout) { - clearTimeout(phone.messageTimeout); - phone.messageTimeout = null; - } - phone.message = null; - phone.messageScrollX = null; - phone.messageType = null; + if (phone.messageTimeout) { + clearTimeout(phone.messageTimeout); + phone.messageTimeout = null; + } + phone.message = null; + phone.messageScrollX = null; + phone.messageType = null; } function phoneNewMessage(type, msg) { - Bangle.buzz(); + Bangle.buzz(); - phoneClearMessage(); - phone.messageTimeout = setTimeout(() => phone.message = null, ONE_SECOND * 30); - phone.message = msg; - phone.messageType = type; + phoneClearMessage(); + phone.messageTimeout = setTimeout(() => phone.message = null, ONE_SECOND * 30); + phone.message = msg; + phone.messageType = type; - // Notify user and active screen - if (!Bangle.isLCDOn()) { - clearTimers(); - Bangle.setLCDPower(true); - } + // Notify user and active screen + if (!Bangle.isLCDOn()) { + clearTimers(); + Bangle.setLCDPower(true); + } } function truncStr(str, max) { @@ -190,15 +190,17 @@ function toggleNightMode() { } function incrementTimer() { - if (timer > 1000) { + if (timer > 100) { timer = 0; } else { - timer += 50; + timer += 10; } } function drawBackground() { + "ram" + // Clear screen const bgColor = (nightMode) ? NIGHT : LIGHTEST; g.setColor(bgColor); @@ -207,10 +209,10 @@ function drawBackground() { // set cloud colors and draw clouds const cloudColor = (nightMode) ? DARK : LIGHT; g.setColor(cloudColor); - g.fillRect(0, 10, g.getWidth(), 15); - g.fillRect(0, 17, g.getWidth(), 17); - g.fillRect(0, 19, g.getWidth(), 19); - g.fillRect(0, 21, g.getWidth(), 21); + g.fillRect(0, 10, W, 15); + g.fillRect(0, 17, W, 17); + g.fillRect(0, 19, W, 19); + g.fillRect(0, 21, W, 21); // Date bar g.setColor(DARKEST); @@ -225,7 +227,9 @@ function drawFloor() { } function drawPyramid() { - const pPol = [pyramidSprite.x + 10, H - 6, pyramidSprite.x + 50, pyramidSprite.height, pyramidSprite.x + 90, H - 6]; // Pyramid poly + "ram" + + const pPol = [pyramidSprite.x + 10, H - 5, pyramidSprite.x + 50, pyramidSprite.height, pyramidSprite.x + 90, H - 5]; // Pyramid poly const color = (nightMode) ? DARK : LIGHT; g.setColor(color); @@ -258,7 +262,7 @@ function drawTrees() { // remove first sprite if offscreen let firstBackgroundSprite = backgroundArr[0]; if (firstBackgroundSprite) { - if (firstBackgroundSprite.x < -15) backgroundArr.splice(0, 1); + if (firstBackgroundSprite.x < -15) backgroundArr.splice(0, 1); } // set background sprite if array empty @@ -304,42 +308,57 @@ function drawCoin() { } function drawDaisyFrame(idx, x, y) { + var frame; + switch(idx) { + case 2: + frame = require("heatshrink").decompress(atob("h0UxH+AAkrAIgAH60rAIQNIBQIABDZErAAwMMBwo0CBxQNEHAQGCBpIPCBoQJCDRIXDBpA7DBIQACw5yCJQgZDP4gNErlcJAZ6GAgNcw+HRI4CCDgNcU44ZDDYSYGDIYACB4QaEDYgMFJAg3DFQ5mFBQYA==")); // daisy jumping + break; case 0: - const dFr1 = require("heatshrink").decompress(atob("h8UxH+AAsHAIgAI60HAIQOJBYIABDpMHAAwNNB4wOJB4gIEHgQBBBxYQCBwYLDDhIaEBxApEw4qDAgIOHDwiIEBwtcFIRWIUgWHw6TIAQXWrlcWZAqBDQIeBBxQaBDxIcCHIQ8JDAIAFWJLPHA==")); - g.drawImage(dFr1, x, y); + frame = require("heatshrink").decompress(atob("h8UxH+AAsHAIgAI60HAIQOJBYIABDpMHAAwNNB4wOJB4gIEHgQBBBxYQCBwYLDDhIaEBxApEw4qDAgIOHDwiIEBwtcFIRWIUgWHw6TIAQXWrlcWZAqBDQIeBBxQaBDxIcCHIQ8JDAIAFWJLPHA==")); break; case 1: default: - const dFr2 = require("heatshrink").decompress(atob("h8UxH+AAsHAIgAI60HAIQOJBYIABDpMHAAwNNB4wOJB4gIEHgQBBBxYQCBwYLDDhIaEBxApEw4qDAgIOHDwiIEBwtcFIRWIUgQvBSZACCBwNcWZQcCAAIPIDgYACFw4YBDYIOCD4waEDYI+HaBQ=")); - g.drawImage(dFr2, x, y); + frame = require("heatshrink").decompress(atob("h8UxH+AAsHAIgAI60HAIQOJBYIABDpMHAAwNNB4wOJB4gIEHgQBBBxYQCBwYLDDhIaEBxApEw4qDAgIOHDwiIEBwtcFIRWIUgQvBSZACCBwNcWZQcCAAIPIDgYACFw4YBDYIOCD4waEDYI+HaBQ=")); } + + g.drawImage(frame, x, y); } function drawMarioFrame(idx, x, y) { + var frame; + switch(idx) { + case 2: + frame = require("heatshrink").decompress(atob("h8UxH+AAkrAAYFCBo9cAAIEB63WB4gMDB4YOFBowfDw4xDBAYADA4YcDGwYACDoYAEBYYBBw4NDCoYOFDIweFFwoZFAQYIDLAQWGEwqgECI6ECJ4JeGQYS9EB4QTHBwImCBYRtDSAwrFawqkFWY7PEBxoMFKoZaELoYICAAg")); // Mario frame jumping + break; case 0: - const mFr1 = require("heatshrink").decompress(atob("h8UxH+AAkHAAYKFBolcAAIPIBgYPDBpgfGFIY7EA4YcEBIPWAAYdDC4gLDAII5ECoYOFDogODFgoJCBwYZCAQYOFBAhAFFwZKGHQpMDw52FSg2HAAIoDAgIOMB5AAFGQTtKeBLuNcQwOJFwgJFA=")); // Mario Frame 1 - g.drawImage(mFr1, x, y); + frame = require("heatshrink").decompress(atob("h8UxH+AAkrAAYKFBolcAAIPIBgYPDBpgfGFIY7EA4YcEBIPWAAYdDC4gLDAII5ECoYOFDogODFgoJCBwYZCAQYOFBAhAFFwZKGGQgNCw4ACLwgFBBwgKECQpZCCgRqDFQikEJIriIBgzwIdxjiGBxIuEBIo=")); // Mario Frame 1 break; case 1: default: - const mFr2 = require("heatshrink").decompress(atob("h8UxH+AAkHAAYKFBolcAAIPIBgYPDBpgfGFIY7EA4YcEBIPWAAYdDC4gLDAII5ECoYOFDogODFgoJCBwYZCAQYOFBAhAFFwZKGHQpMDw+HCQYEBSowOBBQIdCCgTOIFgiVHFwYCBUhA9FBwz8HAo73GACQA=")); // Mario frame 2 - g.drawImage(mFr2, x, y); + frame = require("heatshrink").decompress(atob("h8UxH+AAkrAAYKFBolcAAIPIBgYPDBpgfGFIY7EA4YcEBIPWAAYdDC4gLDAII5ECoYOFDogODFgoJCBwYZCAQYOFBAhAFFwZKGHQpMDw+HCQYEBSowOBBQIeJDAQODSwaVHUhwOLfg4FHe4wASA=")); // Mario frame 2 } + + g.drawImage(frame, x, y); } function drawToadFrame(idx, x, y) { + var frame; + switch(idx) { + case 2: + frame = require("heatshrink").decompress(atob("iEUxH+ACkrAAoNJrnWAAQRGlfWrgACB4QEBCAYOBB44QFB4QICAg4QBBAQbDEgwPCHpAGCGAQ9KAYQPENwoTEH4crw4EDAAgGDB4YABAYIBDP4YLEAAIPHCAQHCCAQTDD4gHDEA4PFGAY3EbooPECob8IPooPFCATGEf44hFAAYLDA==")); // toad jumping + break; case 0: - const tFr1 = require("heatshrink").decompress(atob("iEUxH+ACkHAAoNJrnWAAQRGg/WrgACB4QEBCAYOBB44QFB4QICAg4QBBAQbDEgwPCHpAGCGAQ9KAYQPKCYg/EJAoADAwaKFw4BEP4YQCBIIABB468EB4QADYIoQGDwQOGBYYrCCAwbFFwgQEM4gAEeA4OIH4ghFAAYLD")); // Toad Frame 1 - g.drawImage(tFr1, x, y); + frame = require("heatshrink").decompress(atob("iEUxH+ACkHAAoNJrnWAAQRGg/WrgACB4QEBCAYOBB44QFB4QICAg4QBBAQbDEgwPCHpAGCGAQ9KAYQPKCYg/EJAoADAwaKFw4BEP4YQCBIIABB468EB4QADYIoQGDwQOGBYYrCCAwbFFwgQEM4gAEeA4OIH4ghFAAYLD")); // Toad Frame 1 break; case 1: default: - const tFr2 = require("heatshrink").decompress(atob("iEUxH+ACkHAAoNJrnWAAQRGg/WrgACB4QEBCAYOBB44QFB4QICAg4QBBAQbDEgwPCHpAGCGAQ9KAYQPKCYg/EJAoADAwaKFw4BEP4YQCBIIABB468EB4QADYIoQGDwQOGBYQrDb4wcGFxYLDMoYgHRYgwKABAMBA")); // Mario frame 2 - g.drawImage(tFr2, x, y); + frame = require("heatshrink").decompress(atob("iEUxH+ACkHAAoNJrnWAAQRGg/WrgACB4QEBCAYOBB44QFB4QICAg4QBBAQbDEgwPCHpAGCGAQ9KAYQPKCYg/EJAoADAwaKFw4BEP4YQCBIIABB468EB4QADYIoQGDwQOGBYQrDb4wcGFxYLDMoYgHRYgwKABAMBA")); // Mario frame 2 } + + g.drawImage(frame, x, y); } // Mario speach bubble @@ -363,9 +382,11 @@ function drawNotice(x, y) { } function drawCharacter(date, character) { + "ram" + // calculate jumping const seconds = date.getSeconds(), - milliseconds = date.getMilliseconds(); + milliseconds = date.getMilliseconds(); if (seconds == 59 && milliseconds > 800 && !characterSprite.isJumping) { characterSprite.isJumping = true; @@ -386,9 +407,13 @@ function drawCharacter(date, character) { } // calculate animation timing - if (timer % 50 === 0) { + if (timer % 20 === 0) { // shift to next frame - characterSprite.frameIdx ^= 1; + if (characterSprite.isJumping) { + characterSprite.frameIdx = 2; + } else { + characterSprite.frameIdx = characterSprite.frameIdx == 0 ? 1 : 0; + } } switch(characterSprite.character) { @@ -486,22 +511,22 @@ function drawInfo(date) { } xPos = phone.messageScrollX; } else { - xPos = (W - g.stringWidth(str)) / 2; + xPos = (W - g.stringWidth(str)) / 2; } } else { switch(infoMode) { - case PHON_MODE: - str = buildPhonStr(); - break; - case TEMP_MODE: - str = buildTempStr(); - break; - case BATT_MODE: - str = buildBatStr(); - break; - case DATE_MODE: - default: - str = buildDateStr(date); + case PHON_MODE: + str = buildPhonStr(); + break; + case TEMP_MODE: + str = buildTempStr(); + break; + case BATT_MODE: + str = buildBatStr(); + break; + case DATE_MODE: + default: + str = buildDateStr(date); } xPos = (W - g.stringWidth(str)) / 2; } diff --git a/apps/mclock/ChangeLog b/apps/mclock/ChangeLog index e6a689e9e..cca1b6e6b 100644 --- a/apps/mclock/ChangeLog +++ b/apps/mclock/ChangeLog @@ -1,2 +1,6 @@ 0.02: Modified for use with new bootloader and firmware 0.03: Added Locale based date +0.04: Improve performance, attempt to remove occasional glitch when LCD on (fix #279) +0.05: Add "ram" keyword to allow 2v06 Espruino builds to cache function that needs to be fast + Fix issue where first digit could get stuck going from "2x:xx" to " x:xx" (fix #365) +0.06: Support 12 hour time diff --git a/apps/mclock/clock-morphing.js b/apps/mclock/clock-morphing.js index ce30ad033..15ab206b9 100644 --- a/apps/mclock/clock-morphing.js +++ b/apps/mclock/clock-morphing.js @@ -1,167 +1,182 @@ +var is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; var locale = require("locale"); +var CHARW = 34; // how tall are digits? +var CHARP = 2; // how chunky are digits? +var Y = 50; // start height // Offscreen buffer -var buf = Graphics.createArrayBuffer(240,86,1,{msb:true}); -function flip() { - g.setColor(1,1,1); - g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer},0,50); -} +var buf = Graphics.createArrayBuffer(CHARW+CHARP*2,CHARW*2 + CHARP*2,1,{msb:true}); +var bufimg = {width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer}; // The last time that we displayed -var lastTime = " "; +var lastTime = "-----"; // If animating, this is the interval's id var animInterval; +var timeInterval; /* Get array of lines from digit d to d+1. n is the amount (0..1) maxFive is true is this digit only counts 0..5 */ const DIGITS = { -" ":n=>[], -"0":n=>[ -[n,0,1,0], -[1,0,1,1], -[1,1,1,2], -[n,2,1,2], -[n,1,n,2], -[n,0,n,1]], -"1":n=>[ -[1-n,0,1,0], -[1,0,1,1], -[1-n,1,1,1], -[1-n,1,1-n,2], -[1-n,2,1,2]], -"2":n=>[ -[0,0,1,0], -[1,0,1,1], -[0,1,1,1], -[0,1+n,0,2], -[1,2-n,1,2], -[0,2,1,2]], -"3":n=>[ -[0,0,1-n,0], -[0,0,0,n], -[1,0,1,1], -[0,1,1,1], -[1,1,1,2], -[n,2,1,2]], -"4":n=>[ -[0,0,0,1], -[1,0,1-n,0], -[1,0,1,1-n], -[0,1,1,1], -[1,1,1,2], -[1-n,2,1,2]], -"5": (n,maxFive)=>maxFive ? [ // 5 -> 0 -[0,0,0,1], -[0,0,1,0], -[n,1,1,1], -[1,1,1,2], -[0,2,1,2], -[0,2,0,2], -[1,1-n,1,1], -[0,1,0,1+n]] : [ // 5 -> 6 -[0,0,0,1], -[0,0,1,0], -[0,1,1,1], -[1,1,1,2], -[0,2,1,2], -[0,2-n,0,2]], -"6":n=>[ -[0,0,0,1-n], -[0,0,1,0], -[n,1,1,1], -[1,1-n,1,1], -[1,1,1,2], -[n,2,1,2], -[0,1-n,0,2-2*n]], -"7":n=>[ -[0,0,0,n], -[0,0,1,0], -[1,0,1,1], -[1-n,1,1,1], -[1,1,1,2], -[1-n,2,1,2], -[1-n,1,1-n,2]], -"8":n=>[ -[0,0,0,1], -[0,0,1,0], -[1,0,1,1], -[0,1,1,1], -[1,1,1,2], -[0,2,1,2], -[0,1,0,2-n]], -"9":n=>[ -[0,0,0,1], -[0,0,1,0], -[1,0,1,1], -[0,1,1-n,1], -[0,1,0,1+n], -[1,1,1,2], -[0,2,1,2]], -":":n=>[ -[0.4,0.4,0.6,0.4], -[0.6,0.4,0.6,0.6], -[0.6,0.6,0.4,0.6], -[0.4,0.4,0.4,0.6], -[0.4,1.4,0.6,1.4], -[0.6,1.4,0.6,1.6], -[0.6,1.6,0.4,1.6], -[0.4,1.4,0.4,1.6]] + " ":n=>[], + "0":n=>[ + [n,0,1,0], + [1,0,1,1], + [1,1,1,2], + [n,2,1,2], + [n,1,n,2], + [n,0,n,1]], + "1":n=>[ + [1-n,0,1,0], + [1,0,1,1], + [1-n,1,1,1], + [1-n,1,1-n,2], + [1-n,2,1,2]], + "2":n=>[ + [0,0,1,0], + [1,0,1,1], + [0,1,1,1], + [0,1+n,0,2], + [1,2-n,1,2], + [0,2,1,2]], + "3":n=>[ + [0,0,1-n,0], + [0,0,0,n], + [1,0,1,1], + [0,1,1,1], + [1,1,1,2], + [n,2,1,2]], + "4":n=>[ + [0,0,0,1], + [1,0,1-n,0], + [1,0,1,1-n], + [0,1,1,1], + [1,1,1,2], + [1-n,2,1,2]], + "5to0": n=>[ // 5 -> 0 + [0,0,0,1], + [0,0,1,0], + [n,1,1,1], + [1,1,1,2], + [0,2,1,2], + [0,2,0,2], + [1,1-n,1,1], + [0,1,0,1+n]], + "5to6": n=>[ // 5 -> 6 + [0,0,0,1], + [0,0,1,0], + [0,1,1,1], + [1,1,1,2], + [0,2,1,2], + [0,2-n,0,2]], + "6":n=>[ + [0,0,0,1-n], + [0,0,1,0], + [n,1,1,1], + [1,1-n,1,1], + [1,1,1,2], + [n,2,1,2], + [0,1-n,0,2-2*n]], + "7":n=>[ + [0,0,0,n], + [0,0,1,0], + [1,0,1,1], + [1-n,1,1,1], + [1,1,1,2], + [1-n,2,1,2], + [1-n,1,1-n,2]], + "8":n=>[ + [0,0,0,1], + [0,0,1,0], + [1,0,1,1], + [0,1,1,1], + [1,1,1,2], + [0,2,1,2], + [0,1,0,2-n]], + "9":n=>[ + [0,0,0,1], + [0,0,1,0], + [1,0,1,1], + [0,1,1-n,1], + [0,1,0,1+n], + [1,1,1,2], + [0,2,1,2]], + ":":n=>[ + [0.4,0.4,0.6,0.4], + [0.6,0.4,0.6,0.6], + [0.6,0.6,0.4,0.6], + [0.4,0.4,0.4,0.6], + [0.4,1.4,0.6,1.4], + [0.6,1.4,0.6,1.6], + [0.6,1.6,0.4,1.6], + [0.4,1.4,0.4,1.6]] }; /* Draw a transition between lastText and thisText. 'n' is the amount - 0..1 */ -function draw(lastText,thisText,n) { - buf.clear(); - var x = 1; // x offset - const p = 2; // padding around digits - var y = p; // y offset - const s = 34; // character size +function drawDigits(lastText,thisText,n) { + "ram" + const p = CHARP; // padding around digits + const s = CHARW; // character size + var x = 0; // x offset + g.reset(); for (var i=0;i<lastText.length;i++) { var lastCh = lastText[i]; var thisCh = thisText[i]; if (thisCh==":") x-=4; - var ch, chn = n; - if (lastCh!==undefined && - (thisCh-1==lastCh || - (thisCh==0 && lastCh==5) || - (thisCh==0 && lastCh==9))) - ch = lastCh; - else { - ch = thisCh; - chn = 0; + if (lastCh!=thisCh) { + var ch, chn = n; + if ((thisCh-1==lastCh || + (thisCh==0 && lastCh==5) || + (thisCh==0 && lastCh==9))) + ch = lastCh; + else { + ch = thisCh; + chn = 0; + } + buf.clear(); + if (ch=="5") ch = (lastCh==5 && thisCh==0)?"5to0":"5to6"; + var l = DIGITS[ch](chn); + l.forEach(c=>{ + if (c[0]!=c[2]) // horiz + buf.fillRect(p+c[0]*s,c[1]*s,p+c[2]*s,2*p+c[3]*s); + else if (c[1]!=c[3]) // vert + buf.fillRect(c[0]*s,p+c[1]*s,2*p+c[2]*s,p+c[3]*s); + }); + g.drawImage(bufimg,x,Y); } - var l = DIGITS[ch](chn,lastCh==5 && thisCh==0); - l.forEach(c=>{ - if (c[0]!=c[2]) // horiz - buf.fillRect(x+c[0]*s,y+c[1]*s-p,x+c[2]*s,y+c[3]*s+p); - else if (c[1]!=c[3]) // vert - buf.fillRect(x+c[0]*s-p,y+c[1]*s,x+c[2]*s+p,y+c[3]*s); - }); if (thisCh==":") x-=4; x+=s+p+7; } - y += 2*s; +} +function drawEverythingElse() { + var x = (CHARW + CHARP + 6)*5; + var y = Y + 2*CHARW + CHARP; var d = new Date(); - buf.setFont("6x8"); - buf.setFontAlign(-1,-1); - buf.drawString(("0"+d.getSeconds()).substr(-2), x, y-8); + g.reset(); + g.setFont("6x8"); + g.setFontAlign(-1,-1); + g.drawString(("0"+d.getSeconds()).substr(-2), x, y-8, true); + // meridian + if (is12Hour) g.drawString((d.getHours() < 12) ? "AM" : "PM", x, Y + 4, true); // date - buf.setFontAlign(0,-1); + g.setFontAlign(0,-1); var date = locale.date(d,false); - buf.drawString(date, buf.getWidth()/2, y+8); - flip(); + g.drawString(date, g.getWidth()/2, y+8, true); } /* Show the current time, and animate if needed */ function showTime() { - if (!Bangle.isLCDOn()) return; if (animInterval) return; // in animation - quit var d = new Date(); - var t = (" "+d.getHours()).substr(-2)+":"+ + var hours = d.getHours(); + if (is12Hour) hours = ((hours + 11) % 12) + 1; + var t = (" "+hours).substr(-2)+":"+ ("0"+d.getMinutes()).substr(-2); var l = lastTime; // same - don't animate - if (t==l) { - draw(t,l,0); + if (t==l || l=="-----") { + drawDigits(l,t,0); + drawEverythingElse(); + lastTime = t; return; } var n = 0; @@ -170,23 +185,35 @@ function showTime() { if (n>=1) { n=1; clearInterval(animInterval); - animInterval=0; + animInterval = undefined; } - draw(l,t,n); + drawDigits(l,t,n); }, 20); lastTime = t; } Bangle.on('lcdPower',function(on) { - if (on) + if (animInterval) { + clearInterval(animInterval); + animInterval = undefined; + } + if (timeInterval) { + clearInterval(timeInterval); + timeInterval = undefined; + } + if (on) { showTime(); + timeInterval = setInterval(showTime, 1000); + } else { + lastTime = "-----"; + } }); g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); // Update time once a second -setInterval(showTime, 1000); +timeInterval = setInterval(showTime, 1000); showTime(); // Show launcher when middle button pressed diff --git a/apps/metronome/ChangeLog b/apps/metronome/ChangeLog new file mode 100644 index 000000000..894d62940 --- /dev/null +++ b/apps/metronome/ChangeLog @@ -0,0 +1,6 @@ +0.01: New App! +0.02: Watch vibrates with every beat +0.03: Uses mean of three time intervalls to calculate bmp +0.04: App shows instructions, Widgets remain visible, color changed +0.05: Buzz intensity and beats per bar can be changed via settings-app +0.06: Correct string position diff --git a/apps/metronome/README.md b/apps/metronome/README.md new file mode 100644 index 000000000..f67b4adf1 --- /dev/null +++ b/apps/metronome/README.md @@ -0,0 +1,15 @@ +# Metronome + +This metronome makes your watch blink and vibrate with a given rate. + +## Usage + +* Tap the screen at least three times. The app calculates the mean rate of your tapping. This rate is displayed in bmp while the text blinks and the watch softly vibrates with every beat. +* Use `BTN1` to increase the bmp value by one. +* Use `BTN3` to decrease the bmp value by one. +* You can change the bpm value any time by tapping the screen or using `BTN1` and `BTN3`. +* Intensity of buzzing and the beats per bar (default 4) can be changed with the settings-app. The first beat per bar will be marked in red. + +## Attributions + +Icon made by Roundicons from www.flaticon.com diff --git a/apps/metronome/metronome-icon.js b/apps/metronome/metronome-icon.js new file mode 100644 index 000000000..8b45f233b --- /dev/null +++ b/apps/metronome/metronome-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+ABt4AB4fOFyFOABtUGDotOAAYvcp4ARqovbq0rACAvbqwABF98yGCAvdGAcHgAAEF8tWmIuGGA6QaF4lWFw4vgFwovPmIvuYDIvd0ejF59cF6qQFFwIvnMAguSqxfaFyQvYvOi0QuTF64uCAAQuRXwIvUqouEF6guFF5+cAAiOZF6iOaF5sxv+iF6xfRmVWFwWjv8rp4tSL6YvBqwuDMgQvnFwovURwIvQRggAELygvPgwuIF8ouEBwIvnFwwwXF54uBvwuFq0yF6buCF5guClQuFGAgvfFwcAF49WmIvRFwQvKFwkAmQvHYQMxF7l+FwgvKGAIvalQuGF5dWFx1VABVUvF4p0qAAdPCZNPF51OAD4vOKQIACF/4waF9wuEqgv/F/gwMF97vvAAUqADYtQAAMAADYuRGDgmLA=")) diff --git a/apps/metronome/metronome.js b/apps/metronome/metronome.js new file mode 100644 index 000000000..e5e45559e --- /dev/null +++ b/apps/metronome/metronome.js @@ -0,0 +1,110 @@ +var tStart = Date.now(); +var cindex=0; // index to iterate through colous +var bpm=60; // ininital bpm value +var time_diffs = [1000, 1000, 1000]; //array to calculate mean bpm +var tindex=0; //index to iterate through time_diffs + + +Bangle.setLCDTimeout(undefined); //do not deaktivate display while running this app + +const storage = require("Storage"); +const SETTINGS_FILE = 'metronome.settings.json'; + +//return setting +function setting(key) { + //define default settings + const DEFAULTS = { + 'beatsperbar': 4, + 'buzzintens': 0.75, + }; + if (!settings) { loadSettings(); } + return (key in settings) ? settings[key] : DEFAULTS[key]; +} + +//load settings +let settings; + +function loadSettings() { + settings = storage.readJSON(SETTINGS_FILE, 1) || {}; +} + +function changecolor() { + const colors = { + 0: { value: 0xF800, name: "Red" }, + 1: { value: 0xFFFF, name: "White" }, + 2: { value: 0x9492, name: "gray" }, + 3: { value: 0xFFFF, name: "White" }, + 4: { value: 0x9492, name: "gray" }, + 5: { value: 0xFFFF, name: "White" }, + 6: { value: 0x9492, name: "gray" }, + 7: { value: 0xFFFF, name: "White" }, + }; + g.setColor(colors[cindex].value); + if (cindex == setting('beatsperbar')-1) { + cindex = 0; + } + else { + cindex += 1; + } + return cindex; +} + +function updateScreen() { + g.reset().clearRect(0, 50, 250, 150); + changecolor(); + try { + Bangle.buzz(50, setting('buzzintens')); + } catch(err) { + } + g.setFont("Vector",40).setFontAlign(0,0); + g.drawString(Math.floor(bpm)+"bpm", g.getWidth()/2, 100); +} + +Bangle.on('touch', function(button) { +// setting bpm by tapping the screen. Uses the mean time difference between several tappings. + if (tindex < time_diffs.length) { + if (Date.now()-tStart < 5000) { + time_diffs[tindex] = Date.now()-tStart; + } + } else { + tindex=0; + time_diffs[tindex] = Date.now()-tStart; + } + tindex += 1; + mean_time = 0.0; + for(count = 0; count < time_diffs.length; count++) { + mean_time += time_diffs[count]; + } + time_diff = mean_time/count; + + tStart = Date.now(); + clearInterval(time_diff); + bpm = (60 * 1000/(time_diff)); + updateScreen(); + clearInterval(interval); + interval = setInterval(updateScreen, 60000 / bpm); + return bpm; +}); + +// enable bpm finetuning via buttons. +setWatch(() => { + bpm += 1; + clearInterval(interval); + interval = setInterval(updateScreen, 60000 / bpm); +}, BTN1, {repeat:true}); + +setWatch(() => { + if (bpm > 1) { + bpm -= 1; + clearInterval(interval); + interval = setInterval(updateScreen, 60000 / bpm); + } +}, BTN3, {repeat:true}); + +interval = setInterval(updateScreen, 60000 / bpm); + +g.clear(1).setFont("6x8"); +g.drawString('Touch the screen to set tempo.\nUse BTN1 to increase, and\nBTN3 to decrease bpm value by 1.', 25, 200); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); diff --git a/apps/metronome/metronome_icon.png b/apps/metronome/metronome_icon.png new file mode 100644 index 000000000..4dac7117f Binary files /dev/null and b/apps/metronome/metronome_icon.png differ diff --git a/apps/metronome/settings.js b/apps/metronome/settings.js new file mode 100644 index 000000000..1dd4d92df --- /dev/null +++ b/apps/metronome/settings.js @@ -0,0 +1,48 @@ +// This file should contain exactly one function, which shows the app's settings +/** + * @param {function} back Use back() to return to settings menu + */ +(function(back) { + const SETTINGS_FILE = 'metronome.settings.json'; + + // initialize with default settings... + let s = { + 'beatsperbar': 4, + 'buzzintens': 0.75, + }; + // ...and overwrite them with any saved values + // This way saved values are preserved if a new version adds more settings + const storage = require('Storage'); + const saved = storage.readJSON(SETTINGS_FILE, 1) || {}; + for (const key in saved) { + s[key] = saved[key]; + } + + // creates a function to safe a specific setting, e.g. save('color')(1) + function save(key) { + return function(value) { + s[key] = value; + storage.write(SETTINGS_FILE, s); + }; + } + + const menu = { + '': { 'title': 'Metronome' }, + '< Back': back, + 'beats per bar': { + value: s.beatsperbar, + min: 1, + max: 8, + step: 1, + onchange: save('beatsperbar'), + }, + 'buzz intensity': { + value: s.buzzintens, + min: 0.0, + max: 1.0, + step: 0.25, + onchange: save('buzzintens'), + }, + }; + E.showMenu(menu); +}); diff --git a/apps/miclock/clock-mixed.js b/apps/miclock/clock-mixed.js index bf6efb09e..0bed137c6 100644 --- a/apps/miclock/clock-mixed.js +++ b/apps/miclock/clock-mixed.js @@ -4,73 +4,73 @@ const Radius = { "center": 8, "hour": 78, "min": 95, "dots": 102 }; const Center = { "x": 120, "y": 132 }; function rotatePoint(x, y, d) { - rad = -1 * d / 180 * Math.PI; - var sin = Math.sin(rad); - var cos = Math.cos(rad); - xn = ((Center.x + x * cos - y * sin) + 0.5) | 0; - yn = ((Center.y + x * sin - y * cos) + 0.5) | 0; - p = [xn, yn]; - return p; + rad = -1 * d / 180 * Math.PI; + var sin = Math.sin(rad); + var cos = Math.cos(rad); + xn = ((Center.x + x * cos - y * sin) + 0.5) | 0; + yn = ((Center.y + x * sin - y * cos) + 0.5) | 0; + p = [xn, yn]; + return p; } function drawMixedClock() { - var date = new Date(); - var dateArray = date.toString().split(" "); - var isEn = locale.name.startsWith("en"); - var point = []; - var minute = date.getMinutes(); - var hour = date.getHours(); - var radius; + var date = new Date(); + var dateArray = date.toString().split(" "); + var isEn = locale.name.startsWith("en"); + var point = []; + var minute = date.getMinutes(); + var hour = date.getHours(); + var radius; - // draw date - g.setColor(0x7be0); - g.setFont("6x8", 2); - g.setFontAlign(-1, 0); - g.drawString(locale.dow(date,true) + ' ', 4, 35, true); - g.drawString(isEn?(' ' + dateArray[2]):locale.month(date,true), 4, 225, true); - g.setFontAlign(1, 0); - g.drawString(isEn?locale.month(date,true):(' ' + dateArray[2]), 237, 35, true); - g.drawString(dateArray[3], 237, 225, true); + // draw date + g.setColor(0x7be0); + g.setFont("6x8", 2); + g.setFontAlign(-1, 0); + g.drawString(locale.dow(date,true) + ' ', 4, 35, true); + g.drawString(isEn?(' ' + dateArray[2]):locale.month(date,true), 4, 225, true); + g.setFontAlign(1, 0); + g.drawString(isEn?locale.month(date,true):(' ' + dateArray[2]), 237, 35, true); + g.drawString(dateArray[3], 237, 225, true); - // draw hour and minute dots - g.setColor(0xFD20); // orange - for (i = 0; i < 60; i++) { - radius = (i % 5) ? 2 : 4; - point = rotatePoint(0, Radius.dots, i * 6); - g.fillCircle(point[0], point[1], radius); - } + // draw hour and minute dots + g.setColor(0xFD20); // orange + for (i = 0; i < 60; i++) { + radius = (i % 5) ? 2 : 4; + point = rotatePoint(0, Radius.dots, i * 6); + g.fillCircle(point[0], point[1], radius); + } - // erase last minutes hand - g.setColor(0); - point = rotatePoint(0, Radius.min, (minute - 1) * 6); - g.drawLine(Center.x, Center.y, point[0], point[1]); + // erase last minutes hand + g.setColor(0); + point = rotatePoint(0, Radius.min, (minute - 1) * 6); + g.drawLine(Center.x, Center.y, point[0], point[1]); - // erase last two hour hands - g.setColor(0); - p = rotatePoint(0, Radius.hour, hour % 12 * 30 + (minute - 2) / 2 | 0); - g.drawLine(Center.x, Center.y, p[0], p[1]); - point = rotatePoint(0, Radius.hour, hour % 12 * 30 + (minute - 1) / 2 | 0); - g.drawLine(Center.x, Center.y, point[0], point[1]); + // erase last two hour hands + g.setColor(0); + p = rotatePoint(0, Radius.hour, hour % 12 * 30 + (minute - 2) / 2 | 0); + g.drawLine(Center.x, Center.y, p[0], p[1]); + point = rotatePoint(0, Radius.hour, hour % 12 * 30 + (minute - 1) / 2 | 0); + g.drawLine(Center.x, Center.y, point[0], point[1]); - // draw digital time - g.setFont("6x8", 3); - g.setColor(0x7be0); - g.setFontAlign(0, 0); - g.drawString(dateArray[4].substr(0, 5), 120, 180, true); + // draw digital time + g.setFont("6x8", 3); + g.setColor(0x7be0); + g.setFontAlign(0, 0); + g.drawString(dateArray[4].substr(0, 5), 120, 180, true); - // draw new minute hand - point = rotatePoint(0, Radius.min, minute * 6); - g.setColor(0xFFFF); - g.drawLine(Center.x, Center.y, point[0], point[1]); - // draw new hour hand - point = rotatePoint(0, Radius.hour, hour % 12 * 30 + date.getMinutes() / 2 | 0); - g.setColor(0xFFFF); - g.drawLine(Center.x, Center.y, point[0], point[1]); + // draw new minute hand + point = rotatePoint(0, Radius.min, minute * 6); + g.setColor(0xFFFF); + g.drawLine(Center.x, Center.y, point[0], point[1]); + // draw new hour hand + point = rotatePoint(0, Radius.hour, hour % 12 * 30 + date.getMinutes() / 2 | 0); + g.setColor(0xFFFF); + g.drawLine(Center.x, Center.y, point[0], point[1]); - // draw center - g.setColor(0xFD20); - g.fillCircle(Center.x, Center.y, Radius.center); + // draw center + g.setColor(0xFD20); + g.fillCircle(Center.x, Center.y, Radius.center); } Bangle.on('lcdPower', function(on) { if (on) diff --git a/apps/miclock2/ChangeLog b/apps/miclock2/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/miclock2/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/miclock2/clock-mixed-icon.js b/apps/miclock2/clock-mixed-icon.js new file mode 100644 index 000000000..3ca3b0612 --- /dev/null +++ b/apps/miclock2/clock-mixed-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4ATiwAGFdYzlFp4xeFyYwZD49kxGs2fX6+z1mIsgxcDQtAxArCAA+zxFAGDAYFxAsJAAuIGCxcF1omHgEABI+sGCouERRIvJSgKTEFzovLGAJgRCIiMIF5ySGF57qMF5nXsgvORoggLF5yRPLyAvO6+IF6LsKF6JgEF5lkD5gvPYIiOaF6CQMBYesD5oAP1gvPXxpfDAQIAFYCILDJ5wvP64veACCPeAB6PQd4p9EQQ4MLd6GIF7uIF5YwDsgiNAY4vHsguLYBJfXXxiQKL66ONF4lAL7dAF5pgIF6y9DFxYvEi2sF6+sDwgvLGAryEACLsEFxrCGGCmzXh5gJSQYAPRgovQGA1kMR7qEFyQwHi2IGJWzxCLEFygwIMYOI1gzC2esxBbGFywxKABotXGCwuaGKQtdGZorjAH4A/AF4=")) diff --git a/apps/miclock2/clock-mixed.js b/apps/miclock2/clock-mixed.js new file mode 100644 index 000000000..d928a5185 --- /dev/null +++ b/apps/miclock2/clock-mixed.js @@ -0,0 +1,113 @@ +// Code based on the original Mixed Clock + +/* jshint esversion: 6 */ +var locale = require("locale"); +const Radius = { "center": 7, "hour": 60, "min": 80, "dots": 88 }; +const Center = { "x": 120, "y": 96 }; +const Widths = { hour: 2, minute: 2 }; +var buf = Graphics.createArrayBuffer(240,192,1,{msb:true}); + +function rotatePoint(x, y, d) { + rad = -1 * d / 180 * Math.PI; + var sin = Math.sin(rad); + var cos = Math.cos(rad); + xn = ((Center.x + x * cos - y * sin) + 0.5) | 0; + yn = ((Center.y + x * sin - y * cos) + 0.5) | 0; + p = [xn, yn]; + return p; +} + + +// from https://github.com/espruino/Espruino/issues/1702 +function setLineWidth(x1, y1, x2, y2, lw) { + var dx = x2 - x1; + var dy = y2 - y1; + var d = Math.sqrt(dx * dx + dy * dy); + dx = dx * lw / d; + dy = dy * lw / d; + + return [ + // rounding + x1 - (dx + dy) / 2, y1 - (dy - dx) / 2, + x1 - dx, y1 -dy, + x1 + (dy - dx) / 2, y1 - (dx + dy) / 2, + + x1 + dy, y1 - dx, + x2 + dy, y2 - dx, + + // rounding + x2 + (dx + dy) / 2, y2 + (dy - dx) / 2, + x2 + dx, y2 + dy, + x2 - (dy - dx) / 2, y2 + (dx + dy) / 2, + + x2 - dy, y2 + dx, + x1 - dy, y1 + dx + ]; +} + + +function drawMixedClock(force) { + if ((force || Bangle.isLCDOn()) && buf.buffer) { + var date = new Date(); + var dateArray = date.toString().split(" "); + var isEn = locale.name.startsWith("en"); + var point = []; + var minute = date.getMinutes(); + var hour = date.getHours(); + var radius; + + g.reset(); + buf.clear(); + + // draw date + buf.setFont("6x8", 2); + buf.setFontAlign(-1, 0); + buf.drawString(locale.dow(date,true) + ' ', 4, 16, true); + buf.drawString(isEn?(' ' + dateArray[2]):locale.month(date,true), 4, 176, true); + buf.setFontAlign(1, 0); + buf.drawString(isEn?locale.month(date,true):(' ' + dateArray[2]), 237, 16, true); + buf.drawString(dateArray[3], 237, 176, true); + + // draw hour and minute dots + for (i = 0; i < 60; i++) { + radius = (i % 5) ? 2 : 4; + point = rotatePoint(0, Radius.dots, i * 6); + buf.fillCircle(point[0], point[1], radius); + } + + // draw digital time + buf.setFont("6x8", 3); + buf.setFontAlign(0, 0); + buf.drawString(dateArray[4], 120, 120, true); + + // draw new minute hand + point = rotatePoint(0, Radius.min, minute * 6); + buf.drawLine(Center.x, Center.y, point[0], point[1]); + buf.fillPoly(setLineWidth(Center.x, Center.y, point[0], point[1], Widths.minute)); + // draw new hour hand + point = rotatePoint(0, Radius.hour, hour % 12 * 30 + date.getMinutes() / 2 | 0); + buf.fillPoly(setLineWidth(Center.x, Center.y, point[0], point[1], Widths.hour)); + + // draw center + buf.fillCircle(Center.x, Center.y, Radius.center); + + g.drawImage({width:buf.getWidth(),height:buf.getHeight(),bpp:1,buffer:buf.buffer},0,24); + } +} + +Bangle.on('lcdPower', function(on) { + if (on) + drawMixedClock(true); + Bangle.drawWidgets(); +}); + +setInterval(() => drawMixedClock(true), 30000); // force an update every 30s even screen is off + +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +drawMixedClock(); // immediately draw +setInterval(drawMixedClock, 500); // update twice a second + +// Show launcher when middle button pressed after freeing memory first +setWatch(() => {delete buf.buffer; Bangle.showLauncher()}, BTN2, {repeat:false,edge:"falling"}); diff --git a/apps/miclock2/clock-mixed.png b/apps/miclock2/clock-mixed.png new file mode 100755 index 000000000..f02ad5e9e Binary files /dev/null and b/apps/miclock2/clock-mixed.png differ diff --git a/apps/minionclk/ChangeLog b/apps/minionclk/ChangeLog index 7b83706bf..27dab7259 100755 --- a/apps/minionclk/ChangeLog +++ b/apps/minionclk/ChangeLog @@ -1 +1,4 @@ 0.01: First release +0.02: Improved date readability, fixed drawing of widgets +0.03: Fixed rendering for Espruino v2.06 +0.04: Fixed overlapped rendering of dates diff --git a/apps/minionclk/app.js b/apps/minionclk/app.js index 88fe446ae..f0afbc45c 100755 --- a/apps/minionclk/app.js +++ b/apps/minionclk/app.js @@ -1,14 +1,20 @@ -const bob = require("heatshrink").decompress(atob("nk8hAaXlYLWAEsqvN/0gBBql5lQ2tquj1XV5wBJ52j0hACPsdP1QsBAQQAGBIIBF51/P8OkN5R1GIxF5HLmAFgoDLPZfOpzmZ6vPFwomCPaA6DAYOjeq2A1YyCdI4HGQJQ8F1T2SJ4Oq1XW1es1mtAQOrPoPUAIh3J54ZHIAR5S62s64cBwIBGQIOqHQK4HKQYVDAAIFC1g+BHh9VHAQAFDwQDDHoJ5E54BB6AaBKQ5YGqo6MwJzGHQ4BDeIj/BR4JxDABY8BvI6OOYgaEHwZADHgQ6BZA42GAIusPJNW64eFqzJDlcrERA8BHQI2FqwaBDYYGBPI45GCoIgCLoVWQ5NWXA2rKhaiGLAwOGEAmADxJPDVA51ElQaMC4ouEWALdEHRg8Dc4woCDJo8EAIYxCHQQIFHiwaRegJ5EcYWsHgbrKbBA8GDSrNDO4wfRKgR3FDSh3CN4UrdwZbSHYZ5DHajMFHYQGCHalWO4jtQDQwABwAGCAAQfTKoK0EHahwCeARdFHakASIZWVZ4Q8CO4YgWO4QbCO6hWGEIKYZKzZ3DLog7UG4I6C1lWDSdWO4bpCO4bwUwKYEHajMDwOAlUkLojTUd4gaTZoRWC0YIB1eJLqo4EWiqRE0mjlcr1QkEeKFWOooBCHiB2CC4WA5wzB52rEQgfPHQwABAYJXOHQ2iO4XO6omFEJh1BEAgBGPJlWDIQbC0ej50qgHV1XPEwohKcwRbEvJ3EBQTrLFomkOwOjlR3C5w8GMAR8ClYuBLIgOCvN4HgIZFDQYbBlaOBR4YNCwA5B0XOpzvBHgWqTw4AFxB1EvQ6BAAI8GDZILEdgQBCqp3DPIRfIEQwABvJ1CvGkvGiwA6IAYoBCv6wCAAVOlQ6DAIWkL5ABEwN40Z1CAYJfCv7zEAJNWOYZ3KAIWq5yYHFYLOBLIrVCAIh7BOIzpECoYDDpw7BHAQDG1WqwGkAIN/CwIABLY4LDAAZ9BwAABvLCBC5IBBvOrO44BEAAmjAIPN0XOAJyHIAAgPEquBHBi4BAId+HwWiHxqJDRpYBDq2I1R3LIAQ6BAAOpPogABGgIDDOomk0nP5pIGd42Aq1ewI8CeZI6CHAJhCEAIDCdIo2B0er1esAQIZBC4Z9JlVW1leeKGp0es5+s6+s6ABB0oFBAIervWr0ulub7OqtWmdexJ4BGxB5G0V6pF6wItB0t6p9PvQABvINBudJudPzwXCHQwBDlY6BO4WIwPPPJbvDvA0BFgNzAAIDGugGCzrtHdYh1DAIOBrzxBPIgAIeIXNHgoBCGwYADzoVB0fNOpMyHQdW5+Bro7BHgQAB6jxJAAOjOYhxCAIukOoPN5ujdZFWqyyD0d6AwUrquBwAuB1I1FHgRJBMoQ9BWg1zzw0BDYI6B0R3DAAJ1BvMyp8rAAV4IQWBIodewAeCHAZ5IAAJoBAAXHHAJWDO4TtEdYQvEHgejAwIKClcqIQRdDXYbzFeoQBIGwIDDOot/VgQ6FAAIGBlgBCAAMzmZPBF4LzDACB1FAAOi1WjvFVr0zGYQ7GAAMAAYpPBwNeAIOIwOrfYOA1eA1WkAIWjAIekv4PBwCVBruBq5eBEYIABlcBF4wCEHw55CHwQABIQQBBABkzAILlCHQR1CFYavEPgsAAAIDEDQNdAwQAaHQNWEwQ0DHAh3KleBLoI7dHQKuFWQo0EAIsISoKdBHbyyHNgwADlVVpwEBDANWro7fd4Q6HO495vF5QgIYCd75eBHYUINAN5lQ3EA")); - const locale = require("locale"); -const black = 0x0000; -const white = 0xFFFF; - let hour; let minute; let date; +let timer; + +function getBackground() { + return { + width: 120, + height: 96, + bpp: 8, + buffer: require("heatshrink").decompress(atob("AGkrlcqq0q0nP6vP54HClRN/AEtVqvV1XOAAIDBAJWkqpV/cztV1Wq6vOAIZ4EA4KADAA+jPn50ZMIx2EAAr1MAIN/lUrM34AOqpuDAKYAP0hp/ABbLCMQgDLfJDzO52jlRu/AAsrwHV1TrVeJCWCAZZ5/AAmkLQLtGABYPPeZ1/Ov9V552CbJLzaABujvJ17leAKgzNNeJADPEpejO3TPI6gFFOQxUBCI4BOC4QtFQQkqO21VYonP1XP0uB0gFBOQwAKdpoBD52r1YrB0ZyCAAOpAoVVO23V1fQ1nX1gAGwOrPgLJCAJLrP54tC1otH1YrBPQVPO2WA550GwIBIAAOkdIp0BcI4BGc4IrDE4wABFYmleIVOO2A5BdIxCDAZWr0r1HdJJ1BOhKmMwPPqp1tlZIBJQhOTwLzFeInPAIYlFABr1GFYJ4swHXAAJ2FAB4TEOgbvEAAJ2B1QqDTybzF1d5O1OBJIY4HBIxaL1mq1PO1J4B5ztD1agEcpTxOPAN/O1rhJNxADI1nPeIp2IAIpwMGpJ4mqztJAAlWAIIABAoRMKwOr1bxCPQPV1nXE4wrHAAYrDfBesqp2jlbtIwOCGgMrlYWHR4LpEeI+reIXO652FAIYrQeJZ3jOwTVHqxIHAA5OKAAOj1YpGdoh0IPY7qEeI2BO0jREFwQdSJoLtFEYagKFaikLYB4AQOghKEqwgVlYhHOhTsBFatWd4zwhlfXYogDCOyx4FPRh2YPAYpHJzBSG65KfeKArceIQhDAoglZOwTMEdrTxQwR2bAAKeHF4R4ZDwgBDOzjFGZI4reE5B3adwwkBJTooCeJQqeUYKkHFLJ3BTorCeJhkrFb7qEeIgiYdwggbFJZ4GFUErKYoCBd7DFHO8QqBOw1WFcLwGAoMrEC7FEAAJLiYgZ4EFUJ3CUgwgXJQgDCS64rQAIQqiUYbxEK6+sd4RODJcR3COwh3mFIYDBO652CEAh3jFAJ4EJS6jPd7aXBPAxLjqwrEO8xXFd72sqx3kFYoqjd4TwFd7AgDd9B2DUcrvBKobvZOwoBBJcZzCFYZKXd6iXZJgrDlJoQuCFUUrK46kXYY2BYkZKGO8rvEAYMqEC5MGqxLidwYrDO8TOFAAV5TDJKDYkdW67tEUcmsZwYACwB3XgDvEAYUrJcDuDUgijhlZVEAIWkO7AgGYkNWFI4BBUcCgFAAWjwAiX57FFAAJLgYY4GCUUArGwGpvAjX5ybF1mrJj2BOw4ABAYLweOwjuEAAIiWlXV1mteI1WJTcrJQQnFAIXXPDofBFgYnC0uj1J3XqvO55MGAIJ4aOwYlGeMFWOw+BwDvZqvV52rdoh4cOwLuFPQ4JCPDDtI1h2B0XOd7IABZJTBWORTtCAAZ4YDIJ2BE4x2Bd7nV1eteI5NUlbBFEY7xIUiahBFYIsEEYR0CO7R2BAILLIAIZ5PYAZwHwNWwDxK1lWFZ0rEwJ1Cdo2AdoIBDd7R4DLQ4ADJxS/COwodEwN4vIBBeZAXCAoJ5KHgZ2EFYpyBAAIDCYx7vIAAJ4B5zxLMgjRGdZQBBwF4AAJ4CeIxgIAANWFY6KECYrtFAIMqd7Z4Dao4AGIga9BdYwZEvRyBAAJ4C0iiNF5RBGPAbsCdoYABvTvXOgR6DwDxKKRoPFwByDAIYACFKByECJAABwDtHd7Gqd4oBC0jtGPR4TGOw+kvGjAIKkNEY47IwDtHAYVPO6vPdojxE1WrY5oBKwN6cwYADOgQBBAAJ4NFZtWc4YABd84BCPAjlJdpGANwp0HKAmkdpZ2LvLsDdogAEvJ3WOxTzDG4LrRHoR2QAIWAFaVWv4dHd9YBD52k0o+BJBOA0i9FAJYPHAAJ6DAAYrFFgLrDD4oDId7AABNgQDIAAmq0mAAAYFBHAPOAQLBPAIgADBIl/0l6wNVc4NVOQInU0dOOymBd6B8IAAp4C5oDBAoTBJBoQBHCoYXFABYPMv9WOyVWwPPdIx0JAYWqAIwABMgnNNQwABAZIPJc6wBHldWg53Rq+rd6TzGOwepeIgDCPQ4BTcIwDTdwcylZ3RxOBwLtIdIhyHAIp2BAIN+AIRqQQwKIFAAbVDPgQBCAArvNvNVmZ3SxGswJdBeLD1HAAZmBfIwDLaAek0mr0nPB4b9NAA8rq0zqzvSr2IwDlFNxIDGd4oDBdaABFa4mj1Wl1mr54CB1iWBB4ITDC4wBJOwcIO6OBPAOrPATxYOwS9FLAIAELAILE57jC1elNwIAE1fQ1fO5qSLeIwDDqp2CmcrO6NewNer2A1TlKAZB0EAIPN0WkLooAGb4JoCAI2lPIvPz2dOwjtFAAbtIvB2Clczg7vSxABCwJ4Cd6wAB0XHbAOl62s64BEA4OlvXQBIwKCp9zud6AQIABO4LvLdIoADOwMyd61dr2JwR4BeIZoFA5LvG1JIBp8kp9PvWBdIerMoNIBYNzBoIDCAJAACEoPNOxDtK0Z2CPAZ2RgEy1leAIJ4Cd6jxF5t4NQJsCAAIDJNw10AgZ2DAAOjd5LtEAYbtGAIJ3SleBxFeeYJ4FcooDLd4mp0VOp7lENwzpKPAolC0TvDAAIDDd5FUOwUPOwUyvVUO6OAxJ0Br2CPAWrd7DwBPAThGAApuBAJLtE5p2Dd5AAFdoIABdodWq+j5x2QlXV1R0BPQOBr2seIwADeJTvEKwOjuR4Gp5oDAZdzzojDEAIBBOQbxDdo1VOQUrAYMzeYKCBBoJ3PLoWBPAOBAANdxIDB1RoD6nOAIbxIB4QACPQN4OwR4CNwoBHzwBBNwPNOwQhBPALtJAYdVq52BhB2CPQNV0ecBwMqOxsrLAWADQIBBlVWp53BwDdFAIIALCYIVEKwOdPAb1FABB0B5odBAYLrDAYTtKcoMrAAtWmQPD51UO5tVOwJ0CAAJ6ClcqeoREBAAzxJABDUB0edNwzrEzrFBSQQVBAYZYBAALtKv52CKYgDCqoPBd4IZBO5pWBvQgDPBN/bofNeIRwDAYzxDeorTC0d4zt5zpyDAIJyDCYIFBAIbvC5p2CAAJ2DvEzOgoAFPAPHCoV5Oxcr52rOwmBPAtVwNewOANYR2COAYBILwIAJNAiYCTgILDOw54Dd4p2Cq0zwLMJAAV5d4KkBvB3LwHVqocDEQYACklPU4KCBquqJwYBBNhYLDbYYBTQwZ0GdolUOApTGbQIABlV4C4WiO5bJBEQgBEAAdVAQL7CeQbxOQZT5KfowBCA4LtF0d/qteOxBTFAAaQDqp2JqvODgyVDAYcrmcImczwNceYOAv7fC1SWBAobpYdopyFOIWApy2Bq0zrxABI4R0LAAV4OwIfBO5Oq57rKAAoLBG4OCrter2BwOIAIWrwOswGkwAyBKoJ8GAAJoBAAOq5oFBNQt5vNVwNWAIVdrtWAIJyBOwOBAYJHGA4ZdHp7vC5p3J6uACwQABdYYBFlQDCg4QBOwNePQQABxJ6Cr2CAoIACRANdAI2AA4tdq4TBTwQmDF4IBCVwICDrrtDgLDGJYJdCBQrvC0V5Ow/OO4QABVoIbEOwYABPAcAIoJOCOQIFCAJpmGABczAIZwBAIQABdYIPDJgJHDlcsdopbCeIkq0ej52iOw0rO4NVCQJ2KAI4ABHwIAEdIOCdoWseQL9BAIbhBc4RYBwJgBAYTlFA4NWq5sDcwIJBGgTxCH4JZCdpDuGgEqd4XOlR3FvPV6ulR4gAGFw4HCXIRSBbozxNC4ZwCPwMydYoBHq54CfIg/EOAkAOxAABp/HPAV5O4vVd4OAORABIAAY3Br0rOAZeCAAbtFNAJqDNxgAFA44JDdwZ4EYw5bHzmiAAOjLgmjOwPO0iPHd44sGIAR2BOgTzHQAwAFLwIDHAJjrCPAhDFd4gFDB4150TxB514O4eqd6srhAOBrpDCdZjvFNBzxFAY4yBAAhLFKYgGEKo8r0buBeAkqOwTvCSIggFlQBBqtOVIRSFOwjtCA4YDDcKSANd4p4CAAMBljnIOw53B5wBB0VPO4POOwXOwB2CSIwABvNOAITtCX4bhEdote1j3HeJ4PBC4boGAAw+BIILCDNw7vHgGjAAeigA")) + }; +} + function draw() { const d = new Date(); @@ -19,26 +25,26 @@ function draw() { g.setFontAlign(0, 0, 0); if (newHour !== hour) { - g.setFontVector(48); - g.setColor(black); - g.drawString(hour, 64, 92); - g.setColor(white); - g.drawString(newHour, 64, 92); + g.setFont('6x8', 5); + g.setColor(0x0000); + g.drawString(hour, 76, 100); + g.setColor(0xFFFF); + g.drawString(newHour, 76, 100); hour = newHour; } if (newMinute !== minute) { - g.setFontVector(48); - g.setColor(black); - g.drawString(minute, 172, 92); - g.setColor(white); - g.drawString(newMinute, 172, 92); + g.setFont('6x8', 5); + g.setColor(0x0000); + g.drawString(minute, 164, 100); + g.setColor(0xFFFF); + g.drawString(newMinute, 164, 100); minute = newMinute; } if (newDate !== date) { - g.setFontVector(12); - g.setColor(black); + g.setFont('6x8', 2); + g.setColor(0x0000); g.drawString(date, 120, 228); g.setColor(0xFFFF); g.drawString(newDate, 120, 228); @@ -46,23 +52,33 @@ function draw() { } } -function drawAll() { +function startDrawing() { hour = ''; minute = ''; date = ''; - g.drawImage(bob, 0, 0, { scale: 4 }); + g.setColor(0x0000); + g.fillRect(0, 216, 240, 240); + g.drawImage(getBackground(), 0, 24, { scale: 2 }); + Bangle.drawWidgets(); draw(); + timer = setInterval(draw, 1000); } -Bangle.on('lcdPower', function(on) { +function stopDrawing() { + if (timer) { + clearInterval(timer); + timer = undefined; + } +} + +Bangle.on('lcdPower', (on) => { + stopDrawing(); if (on) { - drawAll(); + startDrawing(); } }); Bangle.loadWidgets(); -Bangle.drawWidgets(); -setInterval(draw, 1000); -drawAll(); +startDrawing(); -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: 'falling' }); diff --git a/apps/miplant/ChangeLog b/apps/miplant/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/miplant/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/miplant/app-icon.js b/apps/miplant/app-icon.js new file mode 100644 index 000000000..bf800ea4c --- /dev/null +++ b/apps/miplant/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+4AA/AH4A/AAPQ64AQ44ZKBYwvc6/QF9wwFF9XXF73I4IAH44/F54vdCpYQESAYvm5Avm44ADA4Yvmc44v/F/4v/F/4v/F/4v+zmjv4ABF9GrwoACrYvn2WGFwgABSh4AV0QtDFwYvmFwlhF9wuDF9QuEF82jFw4vmMIQuFv4vuEDOi0d/WgV/0YNGBIN/LrSvCABAkECAI4GAChKBF5QABCIYEDADKpCsIvJLQQ0EGoShJMBwACSJYvEB5GiMCYxJF4LuCLorTLF6IxGQILuBMYgAGC4QwP0YwHYwQbCF4K1CL4lhCohfQMBBiCFQQvEAgIsFAATxWSQyPDAYYSIHgRgZE4IsBF4QGCCI6NRMBboFXgTTIFyYwIPYWcGAb2CCI2iF6qwBD4aqERYQABIQ+cFywALLwgAqXoYvrSAQROA==")) diff --git a/apps/miplant/app.js b/apps/miplant/app.js new file mode 100644 index 000000000..f26bfc5b8 --- /dev/null +++ b/apps/miplant/app.js @@ -0,0 +1,74 @@ + +function getImgHum() { + return require("heatshrink").decompress(atob("jUoxH+AEtlsoYYDS4ZYDAYaVDLAYFDSQYHDSIZYDBIaPDLAYLDRoZYDBoaLDLAYPDRIZYDCIaHDLAYTDQoZYDCoaDDOQYXAA+JxIYX1utDSwYBAAIzYGiwZUTgpODQpzPGGgY3OdI4aRDIIaMDJIYCDIztDGRwaJP5oaWDAwaRDBAbOC5YcKB5I=")); +} +function getImgTemp() { + return require("heatshrink").decompress(atob("iUqxH+AA2sAAQLHCBASMCAoSLCPOBAAQRfI/5Hn3YACy4ACCL4ADCL5H/I/AQHCRAQJCQwQLCQgQNCQYRQCB4A/ADaPjYqTpSCRYQGCZALFA")); +} +function getImgFert() { + return require("heatshrink").decompress(atob("kklxH+AC+FwtbDbAfFAAVbEbgiGEbYiHEbQiEsIjiEQYjeEQiPdEQrXdEdKnTAAJsMD6QlJFZAAIGAIkPEaIkCrdhEaR9MT4gkLFAyjMYoojNUZ4jFEoxrGEBCJDEZSWEEZdhCwpsKJQiJFAgYgGEQwjLD4QjFCRD+KCAylGQ4gjXVhAiPEhAKDJIwiQEowIEEQo2GERgAKEYwAcEUQkDEL9VAAgHFETgAIDJwePEZwdTE5ggdMJt6AAQEEqwRMABYQDAAwkBF5AkKEBQAPEUR6ESAQicJIX+A==")); +} + +var deviceInfo = {}; + +function parseDevice(device) { + var d = new DataView(device.serviceData["fe95"]); + var frame = d.getUint16(0,true); + var offset = 5; + if (frame&16) offset+=6; // mac address + if (frame&32) offset+=1; // capabilitities + if (frame&64) { // event + var l = d.getUint8(offset+2); + var code = d.getUint16(offset,true); + if (!deviceInfo[device.id]) deviceInfo[device.id]={id:device.id}; + event = deviceInfo[device.id]; + switch (code) { + case 0x1004: event.temperature = d.getInt16(offset+3,true)/10; break; + case 0x1006: event.humidity = d.getInt16(offset+3)/10; break; + case 0x100D: + event.temperature = d.getInt16(offset+3,true)/10; + event.humidity = d.getInt16(offset+5)/10; break; + case 0x1008: event.moisture = d.getUint8(offset+3); break; + case 0x1009: event.fertility = d.getUint16(offset+3,true)/10; break; + // case 0x1007: break; // 3 bytes? got 84,0,0 or 68,0,0 + default: event.code = code; + event.raw = new Uint8Array(d.buffer, offset+3, l); + break; + } + //print(event); + show(event); + } +} + +/* +eg. { + "id": "c4:7c:8d:6a:ac:79 public", + "temperature": 16.6, "code": 4103, + "raw": new Uint8Array([246, 0, 0]), + "moisture": 46, "fertility": 20.8 } +*/ +function show(event) { + g.reset().setFont("6x8"); + var y = 45 + 50*Object.keys(deviceInfo).indexOf(event.id); + + g.drawString(event.id.substr(0,17),0,y); + g.drawImage(getImgHum(),0,y+15); + g.setFont("6x8",2); + var t = (event.moisture===undefined) ? "?" : event.moisture; + g.drawString((t+" ").substr(0,3),35,y+25,true); + g.drawImage(getImgFert(),80,y+15); + t = Math.round(event.fertility) || "?"; + g.drawString((t+" ").substr(0,3), 120, y+25, true); + g.drawImage(getImgTemp(),160,y+15); + t = Math.round(event.temperature) || "?"; + g.drawString((t+" ").substr(0,3), 180, y+25, true); + g.flip(); +} + +g.clear(); +g.setFont("6x8",2).setFontAlign(0,-1).drawString("Scanning...",120,24); + +Bangle.loadWidgets() +Bangle.drawWidgets() + +NRF.setScan(parseDevice, { filters: [{serviceData:{"fe95":{}}}], timeout: 2000 }); diff --git a/apps/miplant/app.png b/apps/miplant/app.png new file mode 100644 index 000000000..d73d3d79a Binary files /dev/null and b/apps/miplant/app.png differ diff --git a/apps/mmonday/manic-monday.js b/apps/mmonday/manic-monday.js index c949fafbf..fd76ee328 100644 --- a/apps/mmonday/manic-monday.js +++ b/apps/mmonday/manic-monday.js @@ -7,12 +7,12 @@ but because we're going lower level we need to account for the different pin. */ if (s.beep=="vib") { function freq(f) { - if (f===0) digitalWrite(D13, 0); + if (f===0) digitalWrite(D13, 0); else analogWrite(D13, 0.1, {freq: f}); } } else { function freq(f) { - if (f===0) digitalWrite(D18, 0); + if (f===0) digitalWrite(D18, 0); else analogWrite(D18, 0.5, {freq: f}); } } diff --git a/apps/moonphase/app.js b/apps/moonphase/app.js index 480a0e144..321e6ab3f 100644 --- a/apps/moonphase/app.js +++ b/apps/moonphase/app.js @@ -8,22 +8,22 @@ var timer; var fix; var PI = Math.PI, - sin = Math.sin, - cos = Math.cos, - tan = Math.tan, - asin = Math.asin, - atan = Math.atan2, - acos = Math.acos, - rad = PI / 180, - dayMs = 1000 * 60 * 60 * 24, - J1970 = 2440588, - J2000 = 2451545; + sin = Math.sin, + cos = Math.cos, + tan = Math.tan, + asin = Math.asin, + atan = Math.atan2, + acos = Math.acos, + rad = PI / 180, + dayMs = 1000 * 60 * 60 * 24, + J1970 = 2440588, + J2000 = 2451545; var SunCalc = {}; //pictures function getImg(i) { - var data = { + var data = { "NewMoon": "AD8AAH/4AHwPgDwA8BwADg4AAcMAADHAAA5gAAGYAABsAAAPAAADwAAA8AAAPAAADwAAA2AAAZgAAGcAADjAAAw4AAcHAAOA8APAHwPgAf/gAA/AAA==", "WaxingCrescentNorth" : "AD8AAH/4AHw/gDwH8BwA/g4AH8MAB/HAAf5gAD+YAA/sAAP/AAD/wAA/8AAP/AAD/wAA/2AAP5gAD+cAB/jAAfw4AH8HAD+A8B/AHw/gAf/gAA/AAA==", "WaningCrescentSouth" : "AD8AAH/4AHw/gDwH8BwA/g4AH8MAB/HAAf5gAD+YAA/sAAP/AAD/wAA/8AAP/AAD/wAA/2AAP5gAD+cAB/jAAfw4AH8HAD+A8B/AHw/gAf/gAA/AAA==", @@ -38,12 +38,12 @@ function getImg(i) { "LastQuarterSouth" : "AD8AAH/4AHx/gDwf8BwH/g4B/8MAf/HAH/5gB/+YAf/sAH//AB//wAf/8AH//AB//wAf/2AH/5gB/+cAf/jAH/w4B/8HAf+A8H/AHx/gAf/gAA/AAA==", "WaningCrescentNorth" : "AD8AAH/4AH8PgD+A8B/ADg/gAcP4ADH+AA5/AAGfwABv8AAP/AAD/wAA/8AAP/AAD/wAA38AAZ/AAGf4ADj+AAw/gAcH8AOA/gPAH8PgAf/gAA/AAA==", "WaxingCrescentSouth" : "AD8AAH/4AH8PgD+A8B/ADg/gAcP4ADH+AA5/AAGfwABv8AAP/AAD/wAA/8AAP/AAD/wAA38AAZ/AAGf4ADj+AAw/gAcH8AOA/gPAH8PgAf/gAA/AAA==" - }; - return { - width : 26, height : 26, bpp : 1, - transparent : 0, - buffer : E.toArrayBuffer(atob(data[i])) - }; + }; + return { + width : 26, height : 26, bpp : 1, + transparent : 0, + buffer : E.toArrayBuffer(atob(data[i])) + }; } // sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas // date/time constants and conversions @@ -59,182 +59,182 @@ function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); } function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; } function astroRefraction(h) { - if (h < 0) // the following formula works for positive altitudes only. - h = 0; // if h = -0.08901179 a div/0 would occur. + if (h < 0) // the following formula works for positive altitudes only. + h = 0; // if h = -0.08901179 a div/0 would occur. - // formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. - // 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad: - return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179)); + // formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. + // 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad: + return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179)); } // general sun calculations function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); } function eclipticLongitude(M) { - var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center - P = rad * 102.9372; // perihelion of the Earth + var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center + P = rad * 102.9372; // perihelion of the Earth - return M + C + P + PI; + return M + C + P + PI; } function sunCoords(d) { - var M = solarMeanAnomaly(d), - L = eclipticLongitude(M); - return { - dec: declination(L, 0), - ra: rightAscension(L, 0) - }; + var M = solarMeanAnomaly(d), + L = eclipticLongitude(M); + return { + dec: declination(L, 0), + ra: rightAscension(L, 0) + }; } // adds a custom time to the times config SunCalc.addTime = function (angle, riseName, setName) { - times.push([angle, riseName, setName]); + times.push([angle, riseName, setName]); }; // moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas function moonCoords(d) { // geocentric ecliptic coordinates of the moon - var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude - M = rad * (134.963 + 13.064993 * d), // mean anomaly - F = rad * (93.272 + 13.229350 * d), // mean distance - l = L + rad * 6.289 * sin(M), // longitude - b = rad * 5.128 * sin(F), // latitude - dt = 385001 - 20905 * cos(M); // distance to the moon in km + var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude + M = rad * (134.963 + 13.064993 * d), // mean anomaly + F = rad * (93.272 + 13.229350 * d), // mean distance + l = L + rad * 6.289 * sin(M), // longitude + b = rad * 5.128 * sin(F), // latitude + dt = 385001 - 20905 * cos(M); // distance to the moon in km - return { - ra: rightAscension(l, b), - dec: declination(l, b), - dist: dt - }; + return { + ra: rightAscension(l, b), + dec: declination(l, b), + dist: dt + }; } SunCalc.getMoonPosition = function (date, lat, lng) { - var lw = rad * -lng, - phi = rad * lat, - d = toDays(date), - c = moonCoords(d), - H = siderealTime(d, lw) - c.ra, - h = altitude(H, phi, c.dec), - // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. - pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H)); - h = h + astroRefraction(h); // altitude correction for refraction - return { - azimuth: azimuth(H, phi, c.dec), - altitude: h, - distance: c.dist, - parallacticAngle: pa - }; + var lw = rad * -lng, + phi = rad * lat, + d = toDays(date), + c = moonCoords(d), + H = siderealTime(d, lw) - c.ra, + h = altitude(H, phi, c.dec), + // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. + pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H)); + h = h + astroRefraction(h); // altitude correction for refraction + return { + azimuth: azimuth(H, phi, c.dec), + altitude: h, + distance: c.dist, + parallacticAngle: pa + }; }; // calculations for illumination parameters of the moon, // based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and // Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. SunCalc.getMoonIllumination = function (date) { - var year = date.getFullYear(); - var month = date.getMonth(); - var day = date.getDate(); - var Moon = { - phases: ['new', 'waxing-crescent', 'first-quarter', 'waxing-gibbous', 'full', 'waning-gibbous', 'last-quarter', 'waning-crescent'], - phase: function (year, month, day) { - let c = 0; - let e = 0; - let jd = 0; - let b = 0; - if (month < 3) { - year--; - month += 12; - } - ++month; - c = 365.25 * year; - e = 30.6 * month; - jd = c + e + day - 694039.09; // jd is total days elapsed - jd /= 29.5305882; // divide by the moon cycle - b = parseInt(jd); // int(jd) -> b, take integer part of jd - jd -= b; // subtract integer part to leave fractional part of original jd - b = Math.round(jd * 8); // scale fraction from 0-8 and round - if (b >= 8) b = 0; // 0 and 8 are the same so turn 8 into 0 - return {phase: b, name: Moon.phases[b]}; - } - }; - return (Moon.phase(year, month, day)); + var year = date.getFullYear(); + var month = date.getMonth(); + var day = date.getDate(); + var Moon = { + phases: ['new', 'waxing-crescent', 'first-quarter', 'waxing-gibbous', 'full', 'waning-gibbous', 'last-quarter', 'waning-crescent'], + phase: function (year, month, day) { + let c = 0; + let e = 0; + let jd = 0; + let b = 0; + if (month < 3) { + year--; + month += 12; + } + ++month; + c = 365.25 * year; + e = 30.6 * month; + jd = c + e + day - 694039.09; // jd is total days elapsed + jd /= 29.5305882; // divide by the moon cycle + b = parseInt(jd); // int(jd) -> b, take integer part of jd + jd -= b; // subtract integer part to leave fractional part of original jd + b = Math.round(jd * 8); // scale fraction from 0-8 and round + if (b >= 8) b = 0; // 0 and 8 are the same so turn 8 into 0 + return {phase: b, name: Moon.phases[b]}; + } + }; + return (Moon.phase(year, month, day)); }; function hoursLater(date, h) { - return new Date(date.valueOf() + h * dayMs / 24); + return new Date(date.valueOf() + h * dayMs / 24); } // calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article SunCalc.getMoonTimes = function (date, lat, lng, inUTC) { - var t = new Date(date); - if (inUTC) t.setUTCHours(0, 0, 0, 0); - else t.setHours(0, 0, 0, 0); - var hc = 0.133 * rad, - h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc, - h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx; + var t = new Date(date); + if (inUTC) t.setUTCHours(0, 0, 0, 0); + else t.setHours(0, 0, 0, 0); + var hc = 0.133 * rad, + h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc, + h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx; - // go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set) - for (var i = 1; i <= 24; i += 2) { - h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc; - h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc; - a = (h0 + h2) / 2 - h1; - b = (h2 - h0) / 2; - xe = -b / (2 * a); - ye = (a * xe + b) * xe + h1; - d = b * b - 4 * a * h1; - roots = 0; - if (d >= 0) { - dx = Math.sqrt(d) / (Math.abs(a) * 2); - x1 = xe - dx; - x2 = xe + dx; - if (Math.abs(x1) <= 1) roots++; - if (Math.abs(x2) <= 1) roots++; - if (x1 < -1) x1 = x2; - } - if (roots === 1) { - if (h0 < 0) rise = i + x1; - else set = i + x1; - } else if (roots === 2) { - rise = i + (ye < 0 ? x2 : x1); - set = i + (ye < 0 ? x1 : x2); - } - if (rise && set) break; - h0 = h2; + // go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set) + for (var i = 1; i <= 24; i += 2) { + h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc; + h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc; + a = (h0 + h2) / 2 - h1; + b = (h2 - h0) / 2; + xe = -b / (2 * a); + ye = (a * xe + b) * xe + h1; + d = b * b - 4 * a * h1; + roots = 0; + if (d >= 0) { + dx = Math.sqrt(d) / (Math.abs(a) * 2); + x1 = xe - dx; + x2 = xe + dx; + if (Math.abs(x1) <= 1) roots++; + if (Math.abs(x2) <= 1) roots++; + if (x1 < -1) x1 = x2; } - var result = {}; - if (rise) result.rise = hoursLater(t, rise); - if (set) result.set = hoursLater(t, set); - if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true; - return result; + if (roots === 1) { + if (h0 < 0) rise = i + x1; + else set = i + x1; + } else if (roots === 2) { + rise = i + (ye < 0 ? x2 : x1); + set = i + (ye < 0 ? x1 : x2); + } + if (rise && set) break; + h0 = h2; + } + var result = {}; + if (rise) result.rise = hoursLater(t, rise); + if (set) result.set = hoursLater(t, set); + if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true; + return result; }; function getMPhaseComp (offset) { - var date = new Date(); - date.setDate(date.getDate() + offset); - var dd = String(date.getDate()); - if(dd<10){dd='0'+dd;} - var mm = String(date.getMonth() + 1); - if(mm<10){mm='0'+mm;} - var yyyy = date.getFullYear(); - var phase = SunCalc.getMoonIllumination(date); - return dd + "." + mm + "." + yyyy + ": "+ phase.name; + var date = new Date(); + date.setDate(date.getDate() + offset); + var dd = String(date.getDate()); + if(dd<10){dd='0'+dd;} + var mm = String(date.getMonth() + 1); + if(mm<10){mm='0'+mm;} + var yyyy = date.getFullYear(); + var phase = SunCalc.getMoonIllumination(date); + return dd + "." + mm + "." + yyyy + ": "+ phase.name; } function getMPhaseSim (offset) { - var date = new Date(); - date.setDate(date.getDate() + offset); - var dd = String(date.getDate()); - if(dd<10){dd='0'+dd;} - var mm = String(date.getMonth() + 1); - if(mm<10){mm='0'+mm;} - var yyyy = date.getFullYear(); - var phase = SunCalc.getMoonIllumination(date); - return phase.name; + var date = new Date(); + date.setDate(date.getDate() + offset); + var dd = String(date.getDate()); + if(dd<10){dd='0'+dd;} + var mm = String(date.getMonth() + 1); + if(mm<10){mm='0'+mm;} + var yyyy = date.getFullYear(); + var phase = SunCalc.getMoonIllumination(date); + return phase.name; } function drawMoonPhase(offset, x, y){ - if (coords.lat >= 0 && coords.lat <= 90){ //Northern hemisphere + if (coords.lat >= 0 && coords.lat <= 90){ //Northern hemisphere if (getMPhaseSim(offset) == "new") {g.drawImage(getImg("NewMoon"), x, y);} if (getMPhaseSim(offset) == "waxing-crescent") {g.drawImage(getImg("WaxingCrescentNorth"), x, y);} if (getMPhaseSim(offset) == "first-quarter") {g.drawImage(getImg("FirstQuarterNorth"), x, y);} @@ -243,8 +243,8 @@ function drawMoonPhase(offset, x, y){ if (getMPhaseSim(offset) == "waning-gibbous") {g.drawImage(getImg("WaningGibbousNorth"), x, y);} if (getMPhaseSim(offset) == "last-quarter") {g.drawImage(getImg("LastQuarterNorth"), x, y);} if (getMPhaseSim(offset) == "waning-crescent") {g.drawImage(getImg("WaningCrescentNorth"), x, y);} -} - else { //Southern hemisphere + } + else { //Southern hemisphere if (getMPhaseSim(offset) == "new") {g.drawImage(getImg("NewMoon"), x, y);} if (getMPhaseSim(offset) == "waxing-crescent") {g.drawImage(getImg("WaxingCrescentSouth"), x, y);} if (getMPhaseSim(offset) == "first-quarter") {g.drawImage(getImg("FirstQuarterSouth"), x, y);} @@ -253,101 +253,101 @@ function drawMoonPhase(offset, x, y){ if (getMPhaseSim(offset) == "waning-gibbous") {g.drawImage(getImg("WaningGibbousSouth"), x, y);} if (getMPhaseSim(offset) == "last-quarter") {g.drawImage(getImg("LastQuarterSouth"), x, y);} if (getMPhaseSim(offset) == "waning-crescent") {g.drawImage(getImg("WaningCrescentSouth"), x, y);} - } + } } function drawMoon(offset, x, y) { - g.setFont("6x8"); - g.clear(); - g.drawString("Key1: day+, Key2:today, Key3:day-",x,y-30); - g.drawString("Last known coordinates: " + coords.lat.toFixed(4) + " " + coords.lon.toFixed(4), x, y-20); - g.drawString("Press BTN4 to update",x, y-10); + g.setFont("6x8"); + g.clear(); + g.drawString("Key1: day+, Key2:today, Key3:day-",x,y-30); + g.drawString("Last known coordinates: " + coords.lat.toFixed(4) + " " + coords.lon.toFixed(4), x, y-20); + g.drawString("Press BTN4 to update",x, y-10); - g.drawString(getMPhaseComp(offset),x,y+30); - drawMoonPhase(offset, x+35, y+40); + g.drawString(getMPhaseComp(offset),x,y+30); + drawMoonPhase(offset, x+35, y+40); - g.drawString(getMPhaseComp(offset+2),x,y+70); - drawMoonPhase(offset+2, x+35, y+80); + g.drawString(getMPhaseComp(offset+2),x,y+70); + drawMoonPhase(offset+2, x+35, y+80); - g.drawString(getMPhaseComp(offset+4),x,y+110); - drawMoonPhase(offset+4, x+35, y+120); + g.drawString(getMPhaseComp(offset+4),x,y+110); + drawMoonPhase(offset+4, x+35, y+120); - g.drawString(getMPhaseComp(offset+6),x,y+150); - drawMoonPhase(offset+6, x+35, y+160); + g.drawString(getMPhaseComp(offset+6),x,y+150); + drawMoonPhase(offset+6, x+35, y+160); } //Write coordinates to file function updateCoords() { - storage.write('coords.json', coords); + storage.write('coords.json', coords); } //set coordinates to default (city where I live) function resetCoords() { - coords = { + coords = { lat : 52.96236, lon : 7.62571, - }; - updateCoords(); + }; + updateCoords(); } function getGpsFix() { - Bangle.on('GPS', function(fix) { - g.clear(); + Bangle.on('GPS', function(fix) { + g.clear(); - if (fix.fix == 1) { - var gpsString = "lat: " + fix.lat.toFixed(4) + " lon: " + fix.lon.toFixed(4); - coords.lat = fix.lat; - coords.lon = fix.lon; - updateCoords(); - g.drawString("Got GPS fix and wrote coords to file",10,20); - g.drawString(gpsString,10,30); - g.drawString("Press BTN5 to return to app",10,40); - clearInterval(timer); - timer = undefined; - } - else { - g.drawString("Searching satellites...",10,20); - g.drawString("Press BTN5 to stop GPS",10, 30); - } - }); + if (fix.fix == 1) { + var gpsString = "lat: " + fix.lat.toFixed(4) + " lon: " + fix.lon.toFixed(4); + coords.lat = fix.lat; + coords.lon = fix.lon; + updateCoords(); + g.drawString("Got GPS fix and wrote coords to file",10,20); + g.drawString(gpsString,10,30); + g.drawString("Press BTN5 to return to app",10,40); + clearInterval(timer); + timer = undefined; + } + else { + g.drawString("Searching satellites...",10,20); + g.drawString("Press BTN5 to stop GPS",10, 30); + } + }); } function start() { - var x = 10; - var y = 50; - var offsetMoon = 0; - coords = storage.readJSON('coords.json',1); //read coordinates from file - if (!coords) resetCoords(); //if coordinates could not be read, reset them + var x = 10; + var y = 50; + var offsetMoon = 0; + coords = storage.readJSON('coords.json',1); //read coordinates from file + if (!coords) resetCoords(); //if coordinates could not be read, reset them + drawMoon(offsetMoon, x, y); //offset, x, y + + //define button functions + setWatch(function() { //BTN1 + offsetMoon++; //jump to next day drawMoon(offsetMoon, x, y); //offset, x, y + }, BTN1, {edge:"rising", debounce:50, repeat:true}); - //define button functions - setWatch(function() { //BTN1 - offsetMoon++; //jump to next day - drawMoon(offsetMoon, x, y); //offset, x, y - }, BTN1, {edge:"rising", debounce:50, repeat:true}); + setWatch(function() { //BTN2 + offsetMoon = 0; //jump to today + drawMoon(offsetMoon, x, y); //offset, x, y + }, BTN2, {edge:"rising", debounce:50, repeat:true}); - setWatch(function() { //BTN2 - offsetMoon = 0; //jump to today - drawMoon(offsetMoon, x, y); //offset, x, y - }, BTN2, {edge:"rising", debounce:50, repeat:true}); + setWatch(function() { //BTN3 + offsetMoon--; //jump to next day + drawMoon(offsetMoon, x, y); //offset, x, y + }, BTN3, {edge:"rising", debounce:50, repeat:true}); - setWatch(function() { //BTN3 - offsetMoon--; //jump to next day - drawMoon(offsetMoon, x, y); //offset, x, y - }, BTN3, {edge:"rising", debounce:50, repeat:true}); + setWatch(function() { //BTN4 + g.drawString("--- Getting GPS signal ---",x, y); + Bangle.setGPSPower(1); + timer = setInterval(getGpsFix, 10000); + }, BTN4, {edge:"rising", debounce:50, repeat:true}); - setWatch(function() { //BTN4 - g.drawString("--- Getting GPS signal ---",x, y); - Bangle.setGPSPower(1); - timer = setInterval(getGpsFix, 10000); - }, BTN4, {edge:"rising", debounce:50, repeat:true}); - - setWatch(function() { //BTN5 - if (timer) clearInterval(timer); - timer = undefined; - Bangle.setGPSPower(0); - drawMoon(offsetMoon, x, y); //offset, x, y - }, BTN5, {edge:"rising", debounce:50, repeat:true}); + setWatch(function() { //BTN5 + if (timer) clearInterval(timer); + timer = undefined; + Bangle.setGPSPower(0); + drawMoon(offsetMoon, x, y); //offset, x, y + }, BTN5, {edge:"rising", debounce:50, repeat:true}); } start(); \ No newline at end of file diff --git a/apps/morse/ChangeLog b/apps/morse/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/morse/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/morse/morse-code.js b/apps/morse/morse-code.js index 72e58d6eb..227aeed81 100644 --- a/apps/morse/morse-code.js +++ b/apps/morse/morse-code.js @@ -95,20 +95,20 @@ const beepItOut = () => { // Could make buzz optional or switchable potentially BUZZING ? Bangle.buzz(UNITS[UNIT_INDEX] === '.' ? UNIT : 3 * UNIT) : null ]) - .then(() => { - if (UNITS[UNIT_INDEX + 1]) { - setTimeout(() => { - UNIT_INDEX++; - beepItOut(); - }, UNIT); - } else { - setTimeout(() => { - BEEPING = false; - UNIT_INDEX = 0; - writeLetter(); - }, 3 * UNIT); - } - }); + .then(() => { + if (UNITS[UNIT_INDEX + 1]) { + setTimeout(() => { + UNIT_INDEX++; + beepItOut(); + }, UNIT); + } else { + setTimeout(() => { + BEEPING = false; + UNIT_INDEX = 0; + writeLetter(); + }, 3 * UNIT); + } + }); }, wait); }; const startBeep = () => { diff --git a/apps/multiclock/ChangeLog b/apps/multiclock/ChangeLog new file mode 100644 index 000000000..2f1d08cc0 --- /dev/null +++ b/apps/multiclock/ChangeLog @@ -0,0 +1,8 @@ +0.01: New App! +0.02: Separate *.face.js files for faces +0.03: Renaming +0.04: Bug Fixes +0.05: Add README +0.06: Add txt clock + + diff --git a/apps/multiclock/README.md b/apps/multiclock/README.md new file mode 100644 index 000000000..5bf6856e5 --- /dev/null +++ b/apps/multiclock/README.md @@ -0,0 +1,49 @@ +# Multiclock + +This is a clock app that supports multiple clock faces. The user can switch between faces while retaining widget state which makes the switch fast and preserves state such as bluetooth connections. Currently there are four clock faces as shown below. To my eye, these faces look better when widgets are hidden using **widviz**. + +### Analog Clock Face +![](anaface.jpg) + +### Digital Clock Face +![](digiface.jpg) + +### Big Digit Clock Face +![](bigface.jpg) + +### Text Clock Face +![](txtface.jpg) + +## Controls +Clock faces are kept in a circular list. + +*BTN1* - switches to the next clock face. + +*BTN2* - switches to the app launcher. + +*BTN3* - switches to the previous clock face. + +## Adding a new face +Clock faces are described in javascript storage files named `name.face.js`. For example, the Analog Clock Face is described in `ana.face.js`. These files have the following structure: + +``` +(() => { + function getFace(){ + function onSecond(){ + //draw digits, hands etc + } + function drawAll(){ + //draw background + initial state of digits, hands etc + } + return {init:drawAll, tick:onSecond}; + } + return getFace; +})(); +``` +For those familiar with the structure of widgets, this is similar, however, there is an additional level of function nesting. This means that although faces are loaded when the clock app starts running they are not instantiated until their `getFace` function is called, i.e. memory is not allocated to structures such as image buffer arrays declared in `getFace` until the face is selected. Consequently, adding a face does not require a lot of extra memory. + +The app at start up loads all files `*.face.js`. The simplest way of adding a face is thus to load it into `Storage` using the WebIDE. Similarly, to remove an unwanted face, simply delete it from `Storage` using the WebIDE. + +## Support + +Please report bugs etc. by raising an issue [here](https://github.com/jeffmer/JeffsBangleAppsDev). \ No newline at end of file diff --git a/apps/multiclock/ana.js b/apps/multiclock/ana.js new file mode 100644 index 000000000..4fd5a7251 --- /dev/null +++ b/apps/multiclock/ana.js @@ -0,0 +1,72 @@ +(() => { + + function getFace(){ + + const p = Math.PI/2; + const PRad = Math.PI/180; + + function seconds(angle, r) { + const a = angle*PRad; + const x = 120+Math.sin(a)*r; + const y = 134-Math.cos(a)*r; + if (angle % 90 == 0) { + g.setColor(0,1,1); + g.fillRect(x-6,y-6,x+6,y+6); + } else if (angle % 30 == 0){ + g.setColor(0,1,1); + g.fillRect(x-4,y-4,x+4,y+4); + } else { + g.setColor(1,1,1); + g.fillRect(x-1,y-1,x+1,y+1); + } + } + + function hand(angle, r1,r2, r3) { + const a = angle*PRad; + g.fillPoly([ + 120+Math.sin(a)*r1, + 134-Math.cos(a)*r1, + 120+Math.sin(a+p)*r3, + 134-Math.cos(a+p)*r3, + 120+Math.sin(a)*r2, + 134-Math.cos(a)*r2, + 120+Math.sin(a-p)*r3, + 134-Math.cos(a-p)*r3]); + } + + var minuteDate; + var secondDate; + + function onSecond() { + g.setColor(0,0,0); + hand(360*secondDate.getSeconds()/60, -5, 90, 3); + if (secondDate.getSeconds() === 0) { + hand(360*(minuteDate.getHours() + (minuteDate.getMinutes()/60))/12, -16, 60, 7); + hand(360*minuteDate.getMinutes()/60, -16, 86, 7); + minuteDate = new Date(); + } + g.setColor(1,1,1); + hand(360*(minuteDate.getHours() + (minuteDate.getMinutes()/60))/12, -16, 60, 7); + hand(360*minuteDate.getMinutes()/60, -16, 86, 7); + g.setColor(0,1,1); + secondDate = new Date(); + hand(360*secondDate.getSeconds()/60, -5, 90, 3); + g.setColor(0,0,0); + g.fillCircle(120,134,2); + } + + function drawAll() { + secondDate = minuteDate = new Date(); + // draw seconds + g.setColor(1,1,1); + for (let i=0;i<60;i++) + seconds(360*i/60, 100); + onSecond(); + } + + return {init:drawAll, tick:onSecond}; + } + +return getFace; + +})(); diff --git a/apps/multiclock/ana.min.js b/apps/multiclock/ana.min.js new file mode 100644 index 000000000..f0c671e97 --- /dev/null +++ b/apps/multiclock/ana.min.js @@ -0,0 +1,2 @@ +(function(){return function(){function e(a,d,b,c){a*=k;g.fillPoly([120+Math.sin(a)*d,134-Math.cos(a)*d,120+Math.sin(a+h)*c,134-Math.cos(a+h)*c,120+Math.sin(a)*b,134-Math.cos(a)*b,120+Math.sin(a-h)*c,134-Math.cos(a-h)*c])}function l(){g.setColor(0,0,0);e(360*f.getSeconds()/60,-5,90,3);0===f.getSeconds()&&(e(360*(d.getHours()+d.getMinutes()/60)/12,-16,60,7),e(360*d.getMinutes()/60,-16,86,7),d=new Date);g.setColor(1,1,1);e(360*(d.getHours()+d.getMinutes()/60)/12,-16,60,7);e(360*d.getMinutes()/60,-16, + 86,7);g.setColor(0,1,1);f=new Date;e(360*f.getSeconds()/60,-5,90,3);g.setColor(0,0,0);g.fillCircle(120,134,2)}var h=Math.PI/2,k=Math.PI/180,d,f;return{init:function(){f=d=new Date;g.setColor(1,1,1);for(var a=0;60>a;a++){var e=360*a/60,b=e*k,c=120+100*Math.sin(b);b=134-100*Math.cos(b);0==e%90?(g.setColor(0,1,1),g.fillRect(c-6,b-6,c+6,b+6)):0==e%30?(g.setColor(0,1,1),g.fillRect(c-4,b-4,c+4,b+4)):(g.setColor(1,1,1),g.fillRect(c-1,b-1,c+1,b+1))}l()},tick:l}}})(); \ No newline at end of file diff --git a/apps/multiclock/anaface.jpg b/apps/multiclock/anaface.jpg new file mode 100644 index 000000000..86aaccd54 Binary files /dev/null and b/apps/multiclock/anaface.jpg differ diff --git a/apps/multiclock/apps_entry.json b/apps/multiclock/apps_entry.json new file mode 100644 index 000000000..91ed12d6c --- /dev/null +++ b/apps/multiclock/apps_entry.json @@ -0,0 +1,18 @@ +{ "id": "multiclock", + "name": "Multi Clock", + "icon": "multiclock.png", + "version":"0.06", + "description": "Clock with multiple faces - Big, Analogue, Digital, Text.\n Switch between faces with BT1 & BTN3", + "readme": "README.md", + "tags": "clock", + "type":"clock", + "allow_emulator":false, + "storage": [ + {"name":"multiclock.app.js","url":"clock.min.js"}, + {"name":"big.face.js","url":"big.min.js"}, + {"name":"ana.face.js","url":"ana.min.js"}, + {"name":"digi.face.js","url":"digi.min.js"}, + {"name":"txt.face.js","url":"txt.min.js"}, + {"name":"multiclock.img","url":"multiclock-icon.js","evaluate":true} + ] + }, diff --git a/apps/multiclock/big.js b/apps/multiclock/big.js new file mode 100644 index 000000000..7580c2427 --- /dev/null +++ b/apps/multiclock/big.js @@ -0,0 +1,32 @@ +(() => { + + function getFace(){ + + function drawTime(d) { + g.reset(); + var da = d.toString().split(" "); + var time = da[4].substr(0, 5).split(":"); + var hours = time[0], + minutes = time[1]; + g.clearRect(0,24,239,239); + g.setColor(1,1,1); + g.setFont("Vector",100); + g.drawString(hours,50,24,true); + g.drawString(minutes,50,135,true); + } + + function onSecond(){ + var t = new Date(); + if (t.getSeconds() === 0) drawTime(t); + } + + function drawAll(){ + drawTime(new Date()); + } + + return {init:drawAll, tick:onSecond}; + } + + return getFace; + +})(); \ No newline at end of file diff --git a/apps/multiclock/big.min.js b/apps/multiclock/big.min.js new file mode 100644 index 000000000..97359511f --- /dev/null +++ b/apps/multiclock/big.min.js @@ -0,0 +1 @@ +(function(){return function(){function c(a){g.reset();var b=a.toString().split(" ")[4].substr(0,5).split(":");a=b[0];b=b[1];g.clearRect(0,24,239,239);g.setColor(1,1,1);g.setFont("Vector",100);g.drawString(a,50,24,!0);g.drawString(b,50,135,!0)}return{init:function(){c(new Date)},tick:function(){var a=new Date;0===a.getSeconds()&&c(a)}}}})(); \ No newline at end of file diff --git a/apps/multiclock/bigface.jpg b/apps/multiclock/bigface.jpg new file mode 100644 index 000000000..685726864 Binary files /dev/null and b/apps/multiclock/bigface.jpg differ diff --git a/apps/multiclock/clock.js b/apps/multiclock/clock.js new file mode 100644 index 000000000..ed2383b8d --- /dev/null +++ b/apps/multiclock/clock.js @@ -0,0 +1,60 @@ +var FACES = []; +var iface = 0; +require("Storage").list(/\.face\.js$/).forEach(face=>FACES.push(eval(require("Storage").read(face)))); +var face = FACES[iface](); +var intervalRefSec; + +function stopdraw() { + if(intervalRefSec) {intervalRefSec=clearInterval(intervalRefSec);} +} + +function startdraw() { + g.clear(); + g.reset(); + Bangle.drawWidgets(); + face.init(); + intervalRefSec = setInterval(face.tick,1000); +} + +function setButtons(){ + function newFace(inc){ + var n = FACES.length-1; + iface+=inc; + iface = iface>n?0:iface<0?n:iface; + stopdraw(); + face = FACES[iface](); + startdraw(); + } + setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); + setWatch(newFace.bind(null,1), BTN1, {repeat:true,edge:"rising"}); + setWatch(newFace.bind(null,-1), BTN3, {repeat:true,edge:"rising"}); +} + +var SCREENACCESS = { + withApp:true, + request:function(){ + this.withApp=false; + stopdraw(); + clearWatch(); + }, + release:function(){ + this.withApp=true; + startdraw(); + setButtons(); + } +}; + +Bangle.on('lcdPower',function(on) { + if (!SCREENACCESS.withApp) return; + if (on) { + startdraw(); + } else { + stopdraw(); + } +}); + +g.clear(); +Bangle.loadWidgets(); +startdraw(); +setButtons(); + diff --git a/apps/multiclock/clock.min.js b/apps/multiclock/clock.min.js new file mode 100644 index 000000000..1eec2b1f5 --- /dev/null +++ b/apps/multiclock/clock.min.js @@ -0,0 +1,3 @@ +var FACES=[],iface=0;require("Storage").list(/\.face\.js$/).forEach(function(a){return FACES.push(eval(require("Storage").read(a)))});var face=FACES[iface](),intervalRefSec;function stopdraw(){intervalRefSec&&(intervalRefSec=clearInterval(intervalRefSec))}function startdraw(){g.clear();g.reset();Bangle.drawWidgets();face.init();intervalRefSec=setInterval(face.tick,1E3)} +function setButtons(){function a(a){var b=FACES.length-1;iface+=a;iface=iface>b?0:0>iface?b:iface;stopdraw();face=FACES[iface]();startdraw()}setWatch(Bangle.showLauncher,BTN2,{repeat:!1,edge:"falling"});setWatch(a.bind(null,1),BTN1,{repeat:!0,edge:"rising"});setWatch(a.bind(null,-1),BTN3,{repeat:!0,edge:"rising"})}var SCREENACCESS={withApp:!0,request:function(){this.withApp=!1;stopdraw();clearWatch()},release:function(){this.withApp=!0;startdraw();setButtons()}}; +Bangle.on("lcdPower",function(a){SCREENACCESS.withApp&&(a?startdraw():stopdraw())});g.clear();Bangle.loadWidgets();startdraw();setButtons(); \ No newline at end of file diff --git a/apps/multiclock/digi.js b/apps/multiclock/digi.js new file mode 100644 index 000000000..f4250bd31 --- /dev/null +++ b/apps/multiclock/digi.js @@ -0,0 +1,31 @@ +(() => { + +function getFace(){ + + var buf = Graphics.createArrayBuffer(240,92,1,{msb:true}); + function flip() { + g.setColor(1,1,1); + g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer},0,85); + } + + function drawTime() { + buf.clear(); + buf.setColor(1); + var d = new Date(); + var da = d.toString().split(" "); + var time = da[4]; + buf.setFont("Vector",42); + buf.setFontAlign(0,-1); + buf.drawString(time,buf.getWidth()/2,0); + buf.setFont("6x8",2); + buf.setFontAlign(0,-1); + var date = d.toString().substr(0,15); + buf.drawString(date, buf.getWidth()/2, 70); + flip(); + } + return {init:drawTime, tick:drawTime}; +} + +return getFace; + +})(); \ No newline at end of file diff --git a/apps/multiclock/digi.min.js b/apps/multiclock/digi.min.js new file mode 100644 index 000000000..1bad4da9e --- /dev/null +++ b/apps/multiclock/digi.min.js @@ -0,0 +1 @@ +(function(){return function(){function b(){a.clear();a.setColor(1);var c=new Date,b=c.toString().split(" ")[4];a.setFont("Vector",42);a.setFontAlign(0,-1);a.drawString(b,a.getWidth()/2,0);a.setFont("6x8",2);a.setFontAlign(0,-1);c=c.toString().substr(0,15);a.drawString(c,a.getWidth()/2,70);g.setColor(1,1,1);g.drawImage({width:a.getWidth(),height:a.getHeight(),buffer:a.buffer},0,85)}var a=Graphics.createArrayBuffer(240,92,1,{msb:!0});return{init:b,tick:b}}})(); \ No newline at end of file diff --git a/apps/multiclock/digiface.jpg b/apps/multiclock/digiface.jpg new file mode 100644 index 000000000..b0323bd55 Binary files /dev/null and b/apps/multiclock/digiface.jpg differ diff --git a/apps/multiclock/multiclock-icon.js b/apps/multiclock/multiclock-icon.js new file mode 100644 index 000000000..41a59f503 --- /dev/null +++ b/apps/multiclock/multiclock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkEogA/AFGIAAQVVDKQWHDB1IC5OECx8z///mYYOBoWDCoIADnBJLFwQWGDAgwIEYU/CQXwh4EC+YwKBIOPFQYXE//4C5BGCIQgXF/5IILo4XGMIQXHLoYXIMIRGMC45IHC4KkGC45IBC4yNEC5KRBC7h2HC5B4GC5EggQXOBwvygEAl6QHC4sikRGEhGAJAgNBC75HIgZHNO48AgIJER54xCiYXKa5AxCGAjvPGA4XIwYXHbQs4C46QGGAbZDB4IXEPBQAEOwwXDJBJGEC4xILIxQwDSJCNDFwwXDMIh0ELoQXIJARhDC4hdCIw4wEDAQXDCwQuIGAgABmYXBmYHDFxIYGAAoWLJIgAGCxgYJCxwZGCqIA/AC4A=")) diff --git a/apps/multiclock/multiclock.png b/apps/multiclock/multiclock.png new file mode 100644 index 000000000..751f4ec00 Binary files /dev/null and b/apps/multiclock/multiclock.png differ diff --git a/apps/multiclock/txt.js b/apps/multiclock/txt.js new file mode 100644 index 000000000..805342bf7 --- /dev/null +++ b/apps/multiclock/txt.js @@ -0,0 +1,42 @@ +(() => { + + function getFace(){ + + function drawTime(d) { + function convert(n){ + var t0 = [" ","one","two","three","four","five","six","seven","eight","nine"]; + var t1 = ["ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"]; + var t20= ["twenty","thirty","forty","fifty"]; + if(n<10) return {top:" ",bot:t0[n]}; + else if(n<20) return {top:" ",bot:t1[n-10]}; + else if(n<60) return {top:t20[Math.floor(n/10)-2],bot:t0[n%10]}; + return "error"; + } + g.reset(); + g.clearRect(0,40,239,210); + g.setColor(1,1,1); + g.setFontAlign(0,0); + g.setFont("Vector",32); + var txt = convert(d.getHours()); + g.drawString(txt.top,120,60); + g.drawString(txt.bot,120,100); + txt = convert(d.getMinutes()); + g.drawString(txt.top,120,140); + g.drawString(txt.bot,120,180); + } + + function onSecond(){ + var t = new Date(); + if (t.getSeconds() === 0) drawTime(t); + } + + function drawAll(){ + drawTime(new Date()); + } + + return {init:drawAll, tick:onSecond}; + } + +return getFace; + +})(); \ No newline at end of file diff --git a/apps/multiclock/txt.min.js b/apps/multiclock/txt.min.js new file mode 100644 index 000000000..144c36d02 --- /dev/null +++ b/apps/multiclock/txt.min.js @@ -0,0 +1,2 @@ +(function(){return function(){function a(b){function a(c){var a=" ;one;two;three;four;five;six;seven;eight;nine".split(";"),b="ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen".split(" "),d=["twenty","thirty","forty","fifty"];return 10>c?{top:" ",bot:a[c]}:20>c?{top:" ",bot:b[c-10]}:60>c?{top:d[Math.floor(c/10)-2],bot:a[c%10]}:"error"}g.reset();g.clearRect(0,40,239,210);g.setColor(1,1,1);g.setFontAlign(0,0);g.setFont("Vector",32);var d=a(b.getHours());g.drawString(d.top, +120,60);g.drawString(d.bot,120,100);d=a(b.getMinutes());g.drawString(d.top,120,140);g.drawString(d.bot,120,180)}return{init:function(){a(new Date)},tick:function(){var b=new Date;0===b.getSeconds()&&a(b)}}}})(); \ No newline at end of file diff --git a/apps/multiclock/txtface.jpg b/apps/multiclock/txtface.jpg new file mode 100644 index 000000000..e38341257 Binary files /dev/null and b/apps/multiclock/txtface.jpg differ diff --git a/apps/nato/nato.js b/apps/nato/nato.js index f4301b83f..e9bbd9bba 100644 --- a/apps/nato/nato.js +++ b/apps/nato/nato.js @@ -53,7 +53,7 @@ const writeText = (txt) => { var width = g.stringWidth(txt); - // Fit text to screen + // Fit text to screen var fontFix = FONT_SIZE; while(width > SCREEN_PIXELS-10){ fontFix--; diff --git a/apps/ncfrun/ChangeLog b/apps/ncfrun/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/ncfrun/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/ncfrun/nceu-funrun.js b/apps/ncfrun/nceu-funrun.js index cd2fab866..30e587188 100644 --- a/apps/ncfrun/nceu-funrun.js +++ b/apps/ncfrun/nceu-funrun.js @@ -118,7 +118,7 @@ function arrow(r,c) { 180+20*Math.sin(r+p), 180-20*Math.cos(r+p), 180-10*Math.sin(r), 180+10*Math.cos(r), 180+20*Math.sin(r+-p), 180-20*Math.cos(r-p), - ]); + ]); } function onCompass(m) { diff --git a/apps/ncstart/ChangeLog b/apps/ncstart/ChangeLog index f4418827e..152fdc9d1 100644 --- a/apps/ncstart/ChangeLog +++ b/apps/ncstart/ChangeLog @@ -5,3 +5,5 @@ 0.04: Run again when updated Don't run again when settings app is updated (or absent) Add "Run Now" option to settings +0.05: Don't overwrite existing settings on app update +0.06: Allow welcome to run after a fresh install diff --git a/apps/ncstart/boot.js b/apps/ncstart/boot.js index e3f514f5b..62ac962f6 100644 --- a/apps/ncstart/boot.js +++ b/apps/ncstart/boot.js @@ -1,11 +1,8 @@ (function() { - let s = require('Storage').readJSON('ncstart.settings.json', 1) - || require('Storage').readJSON('setting.json', 1) - || {welcomed: true} // do NOT run if global settings are also absent - if (!s.welcomed && require('Storage').read('ncstart.app.js')) { + let s = require('Storage').readJSON('ncstart.json', 1) || {}; + if (!s.welcomed) { setTimeout(() => { - s.welcomed = true - require('Storage').write('ncstart.settings.json', s) + require('Storage').write('ncstart.json', {welcomed: true}) load('ncstart.app.js') }) } diff --git a/apps/ncstart/settings-default.json b/apps/ncstart/settings-default.json deleted file mode 100644 index d250efff5..000000000 --- a/apps/ncstart/settings-default.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "welcomed": false -} diff --git a/apps/ncstart/settings.js b/apps/ncstart/settings.js index 2b24095cf..560fad8ba 100644 --- a/apps/ncstart/settings.js +++ b/apps/ncstart/settings.js @@ -1,13 +1,12 @@ -// The welcome app is special, and gets to use global settings (function(back) { - let settings = require('Storage').readJSON('ncstart.settings.json', 1) + let settings = require('Storage').readJSON('ncstart.json', 1) || require('Storage').readJSON('setting.json', 1) || {} E.showMenu({ '': { 'title': 'NCEU Startup' }, 'Run on Next Boot': { value: !settings.welcomed, format: v => v ? 'OK' : 'No', - onchange: v => require('Storage').write('ncstart.settings.json', {welcomed: !v}), + onchange: v => require('Storage').write('ncstart.json', {welcomed: !v}), }, 'Run Now': () => load('ncstart.app.js'), '< Back': back, diff --git a/apps/notify/ChangeLog b/apps/notify/ChangeLog new file mode 100644 index 000000000..cb974e12d --- /dev/null +++ b/apps/notify/ChangeLog @@ -0,0 +1,3 @@ +0.01: New Library! +0.02: Add notification ID option +0.03: Pass `area{x,y,w,h}` to render callback instead of just `y` \ No newline at end of file diff --git a/apps/notify/README.md b/apps/notify/README.md new file mode 100644 index 000000000..cef9f2124 --- /dev/null +++ b/apps/notify/README.md @@ -0,0 +1,39 @@ +# Notifications (default) + +A handler for displaying notifications that displays them in a bar at the top of the screen + +This is not an app, but instead it is a library that can be used by +other applications or widgets to display messages. + +## Usage + +```JS +options = { + on : bool, // turn screen on, default true + size : int, // height of notification, default 80 (max) + title : string, // optional title + id // optional notification ID, used with hide() + src : string, // optional source name + body : string, // optional body text + icon : string, // optional icon (image string) + render function(area) {} // function callback to render in area{x,y,w,h} +}; +// eg... show notification +require("notify").show({title:"Test", body:"Hello"}); +// or display lots of text, with a phone icon +require("notify").show({ + title:"Hello", + src:"Test", + body:"This is a really really really long bit of text that has to be wrapped", + icon:require("heatshrink").decompress(atob("jEYxH+ACcejwUUAAYWVjESCqoABCqoYNCpQXLCxgXJQowtTA4ZbSZiwW/C4gWWjAXVZwIuVWhxFIC6z6OLpIXSCywXYDAIWVAAYXTA==")) +}); +// remove it (can also be removed by tapping) +require("notify").hide(); + +// Use ID to only hide a specific notification if it is still visible +require("notify").show({id:1, title:"Test", body:"Some Alert"}); +require("notify").show({id:"msg", title:"Message", body:"Incoming Message"}); // replaces Test Alert +require("notify").hide({id:1}); // does nothing, because the Test Alert was already replaced +require("notify").hide({id:"msg"}); // hides Message +require("notify").hide(); // hides current notification, whatever it was +``` diff --git a/apps/notify/notify.js b/apps/notify/notify.js new file mode 100644 index 000000000..d8168e048 --- /dev/null +++ b/apps/notify/notify.js @@ -0,0 +1,153 @@ +let pos = 0; +let id = null; + +/** + * Fit text into area, trying to insert newlines between words + * Appends "..." if more text was present but didn't fit + * + * @param {string} text + * @param {number} rows Maximum number of rows + * @param {number} width Maximum line length, in characters + */ +function fitWords(text,rows,width) { + // We never need more than rows*width characters anyway, split by any whitespace + const words = text.trim().substr(0,rows*width).split(/\s+/); + let row=1,len=0,limit=width; + let result = ""; + for (let word of words) { + // len==0 means first word of row, after that we also add a space + if ((len?len+1:0)+word.length > limit) { + if (row>=rows) { + result += "..."; + break; + } + result += "\n"; + len=0; + row++; + if (row===rows) limit -= 3; // last row needs space for "..." + } + result += (len?" ":"") + word; + len += (len?1:0) + word.length; + } + return result; +} + +/** + options = { + on : bool // turn screen on, default true + size : int // height of notification, default 80 (max) + title : string // optional title + id // optional notification ID, used with hide() + src : string // optional source name + body : string // optional body text + icon : string // optional icon (image string) + render function(y) // function callback to render + } +*/ +/* + The screen is 240x240px, but has a 240x320 buffer, used like this: + 0,0: top-left ... 239,0: top-right + [Normal screen contents: lines 0-239] + 239,0: bottom-left ... 239,239: bottom-right + [Usually off-screen: lines 240-319] + 319,0: last line in buffer ... 319,239: last pixel in buffer + + When moving the display area, the buffer wraps around + + So we draw notifications at the end of the buffer, + then shift the display down to show them without touching regular content. + Apps don't know about this, so can just keep updating the usual display area. + + For example, a size 40 notification: + - Draws in bottom 40 buffer lines (279-319) + - Shifts display down by 40px + Display now shows buffer lines 279-319,0-199 + Apps/widgets keep drawing to buffer line 0-239 like nothing happened + */ +exports.show = function(options) { + options = options || {}; + if (options.on===undefined) options.on = true; + id = ("id" in options)?options.id:null; + let size = options.size || 80; + if (size>80) {size = 80} + const oldMode = Bangle.getLCDMode(); + // TODO: throw exception if double-buffered? + // TODO: throw exception if size>80? + + Bangle.setLCDMode("direct"); + // drawing area + let x = 0, + y = 320-size, + w = 240, + h = size, + b = y+h-1, r = x+w-1; // bottom,right + g.setClipRect(x,y, r,b); + // clear area + g.setColor(0).fillRect(x,y, r,b); + // bottom border + g.setColor(0x39C7).fillRect(0,b-1, r,b); + b -= 2;h -= 2; + // title bar + if (options.title || options.src) { + g.setColor(0x39C7).fillRect(x,y, r,y+20); + const title = options.title||options.src; + g.setColor(-1).setFontAlign(-1, -1, 0).setFont("6x8", 2); + g.drawString(title.trim().substring(0, 13), x+25,y+3); + if (options.title && options.src) { + g.setFont("6x8", 1); + g.drawString(options.src.substring(0, 10), x+215,y+5); + } + y += 20;h -= 20; + } + if (options.icon) { + let i = options.icon, iw; + g.drawImage(i, x,y+4); + if ("string"==typeof i) {iw = i.charCodeAt(0)} + else {iw = i[0]} + x += iw;w -= iw; + } + // body text + if (options.body) { + const maxRows=Math.floor((h-4)/8), // font=6x8 + maxChars=Math.floor(w/6)-2, + text=fitWords(options.body, maxRows, maxChars); + g.setColor(-1).setFont("6x8", 1).setFontAlign(-1, -1, 0).drawString(text, x+6,y+4); + } + + if (options.render) { + options.render({x:x, y:y, w:w, h:h}); + } + + if (options.on) Bangle.setLCDPower(1); // light up + Bangle.setLCDMode(oldMode); // clears cliprect + + function anim() { + pos -= 2; + if (pos < -size) { + pos = -size; + } + Bangle.setLCDOffset(pos); + if (pos > -size) setTimeout(anim, 15); + } + anim(); + Bangle.on("touch", exports.hide); +} + +/** + options = { + id // optional, only hide if current notification has this ID + } +*/ +exports.hide = function(options) { + options = options||{}; + if ("id" in options && options.id!==id) return; + id = null; + Bangle.removeListener("touch", exports.hide); + function anim() { + pos += 4; + if (pos > 0) pos = 0; + Bangle.setLCDOffset(pos); + if (pos < 0) setTimeout(anim, 10); + } + anim(); +} diff --git a/apps/notify/notify.png b/apps/notify/notify.png new file mode 100644 index 000000000..cea7a2d07 Binary files /dev/null and b/apps/notify/notify.png differ diff --git a/apps/notifyfs/ChangeLog b/apps/notifyfs/ChangeLog new file mode 100644 index 000000000..b359d314b --- /dev/null +++ b/apps/notifyfs/ChangeLog @@ -0,0 +1,5 @@ +0.01: New Library! +0.02: Add notification ID option +0.03: Fix custom render callback +0.04: Pass `area{x,y,w,h}` to render callback instead of just `y` +0.05: Fix `g` corruption issue if .hide gets called twice diff --git a/apps/notifyfs/notify.js b/apps/notifyfs/notify.js new file mode 100644 index 000000000..74a8d4912 --- /dev/null +++ b/apps/notifyfs/notify.js @@ -0,0 +1,124 @@ +let oldg; +let id = null; + +/** + * See notify/notify.js + */ +function fitWords(text,rows,width) { + // We never need more than rows*width characters anyway, split by any whitespace + const words = text.trim().substr(0,rows*width).split(/\s+/); + let row=1,len=0,limit=width; + let result = ""; + for (let word of words) { + // len==0 means first word of row, after that we also add a space + if ((len?len+1:0)+word.length > limit) { + if (row>=rows) { + result += "..."; + break; + } + result += "\n"; + len=0; + row++; + if (row===rows) limit -= 3; // last row needs space for "..." + } + result += (len?" ":"") + word; + len += (len?1:0) + word.length; + } + return result; +} + + +/** + options = { + on : bool // turn screen on, default true + size : int // height of notification, default 120 (max) + title : string // optional title + id // optional notification ID, used with hide() + src : string // optional source name + body : string // optional body text + icon : string // optional icon (image string) + render function(y) // function callback to render + } +*/ +exports.show = function(options) { + if (oldg) g=oldg; + options = options||{}; + if (options.on===undefined) options.on=true; + id = ("id" in options)?options.id:null; + let size = options.size||120; + if (size>120) {size=120} + Bangle.setLCDMode("direct"); + let x = 0, + y = 0, + w = 240, + h = 240; + // clear screen + g.clear(1); + // top bar + if (options.title||options.src) { + y=40;h=size; + const title = options.title || options.src + g.setColor(0x39C7).fillRect(x, y, x+w-1, y+30); + g.setColor(-1).setFontAlign(-1, -1, 0).setFont("6x8", 3); + g.drawString(title.trim().substring(0, 13), x+5, y+3); + if (options.title && options.src) { + g.setColor(-1).setFontAlign(1, 1, 0).setFont("6x8", 2); + // above drawing area, but we are fullscreen + g.drawString(options.src.substring(0, 10), x+235, y-32); + } + y += 30;h -= 30; + } + if (options.icon) { + let i = options.icon, iw,ih; + if ("string"==typeof i) {iw=i.charCodeAt(0); ih=i.charCodeAt(1)} + else {iw=i[0]; ih=i[1]} + const iy=y ? (y+4) : (h-ih)/2; // show below title bar if present, otherwise center vertically + g.drawImage(i, x+4,iy); + x += iw+4;w -= iw+4; + } + // body text + if (options.body) { + const maxRows = Math.floor((h-4)/16), // font=2*(6x8) + maxChars = Math.floor((w-4)/12), + text=fitWords(options.body, maxRows, maxChars); + g.setColor(-1).setFont("6x8", 2).setFontAlign(-1, -1, 0).drawString(text, x+4, y+4); + } + + if (options.render) { + const area={x:x, y:y, w:w, h:h} + options.render(area); + } + + if (options.on) Bangle.setLCDPower(1); // light up + Bangle.on("touch", exports.hide); + // Create a fake graphics to hide draw attempts + oldg = g; + g = Graphics.createArrayBuffer(8,8,1); + g.flip = function() {}; +}; + +/** + options = { + id // optional, only hide if current notification has this ID + } + */ +exports.hide = function(options) { + options = options||{}; + if ("id" in options && options.id!==id) return; + id = null; + if (oldg) { + g=oldg; + oldg = undefined; + } + Bangle.removeListener("touch", exports.hide); + g.clear(); + Bangle.drawWidgets(); + // flipping the screen off then on often triggers a redraw - it may not! + Bangle.setLCDPower(0); + Bangle.setLCDPower(1); + // hack for E.showMenu/showAlert/showPrompt - can force a redraw by faking next/back + if (Bangle.btnWatches) { + global["\xff"].watches[Bangle.btnWatches[0]].callback(); + global["\xff"].watches[Bangle.btnWatches[1]].callback(); + } +}; diff --git a/apps/notifyfs/notify.png b/apps/notifyfs/notify.png new file mode 100644 index 000000000..cea7a2d07 Binary files /dev/null and b/apps/notifyfs/notify.png differ diff --git a/apps/numerals/ChangeLog b/apps/numerals/ChangeLog index ec465a83f..2869074a6 100644 --- a/apps/numerals/ChangeLog +++ b/apps/numerals/ChangeLog @@ -1,3 +1,8 @@ 0.01: New App! 0.02: Use BTN2 for settings menu like other clocks -0.03: maximize numerals, make menu button configurable, change icon to mac palette, add default settings file, respect 12hour setting \ No newline at end of file +0.03: maximize numerals, make menu button configurable, change icon to mac palette, add default settings file, respect 12hour setting +0.04: Don't overwrite existing settings on app update +0.05: Fix settings issue +0.06: Improve rendering of Numeral 1, fix issue with alarms not showing up +0.07: Add date on touch and some improvements (see settings and readme) +0.08: Add new draw styles, tidy up draw functionality diff --git a/apps/numerals/README.md b/apps/numerals/README.md index 52e84c76d..ebf4c10fe 100644 --- a/apps/numerals/README.md +++ b/apps/numerals/README.md @@ -17,4 +17,7 @@ Settings can be accessed through the app/widget settings menu of the Bangle.js * frame - only shows outline of numerals ### Menu button -* choose button to start launcher menu with \ No newline at end of file +* choose button to start launcher menu with + +### Date on touch +* shows the current date as DD MM on touch and reverts back to time after 5 seconds \ No newline at end of file diff --git a/apps/numerals/numerals-default.json b/apps/numerals/numerals-default.json deleted file mode 100644 index aa6a25047..000000000 --- a/apps/numerals/numerals-default.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - color:0, - drawMode:"fill", - menuButton:22 -} \ No newline at end of file diff --git a/apps/numerals/numerals.app.js b/apps/numerals/numerals.app.js index b24e8bc5e..49a41732e 100644 --- a/apps/numerals/numerals.app.js +++ b/apps/numerals/numerals.app.js @@ -8,7 +8,7 @@ var numerals = { 0:[[9,1,82,1,90,9,90,92,82,100,9,100,1,92,1,9],[30,25,61,25,69,33,69,67,61,75,30,75,22,67,22,33]], - 1:[[59,1,82,1,90,9,90,92,82,100,73,100,65,92,65,27,59,27,51,19,51,9]], + 1:[[50,1,82,1,90,9,90,92,82,100,73,100,65,92,65,27,50,27,42,19,42,9]], 2:[[9,1,82,1,90,9,90,53,82,61,21,61,21,74,82,74,90,82,90,92,82,100,9,100,1,92,1,48,9,40,70,40,70,27,9,27,1,19,1,9]], 3:[[9,1,82,1,90,9,90,92,82,100,9,100,1,92,1,82,9,74,70,74,70,61,9,61,1,53,1,48,9,40,70,40,70,27,9,27,1,19,1,9]], 4:[[9,1,14,1,22,9,22,36,69,36,69,9,77,1,82,1,90,9,90,92,82,100,78,100,70,92,70,61,9,61,1,53,1,9]], @@ -24,72 +24,97 @@ var _mCol = ["#55ff55","#ffffff","#00EFEF","#FFBF00"]; var _rCol = 0; var interval = 0; const REFRESH_RATE = 10E3; +var drawFuncs = { + fill : function(poly,isHole){ + if (isHole) g.setColor(0); + g.fillPoly(poly,true); + }, + framefill : function(poly,isHole){ + var c = g.getColor(); + g.setColor(isHole ? 0 : ((c&0b1111011111011110)>>1)); // 16 bit half bright + g.fillPoly(poly,true); + g.setColor(c); + g.drawPoly(poly,true); + }, + frame : function(poly,isHole){ + g.drawPoly(poly,true); + }, + thickframe : function(poly,isHole){ + g.drawPoly(poly,true); + g.drawPoly(translate(1,0,poly),true); + g.drawPoly(translate(1,1,poly),true); + g.drawPoly(translate(0,1,poly),true); + } +}; function translate(tx, ty, p){ - return p.map((x, i)=> x+((i%2)?ty:tx)); + return p.map((x, i)=> x+((i&1)?ty:tx)); } -function fill(poly){ - return g.fillPoly(poly,true); -} - -function frame(poly){ - return g.drawPoly(poly,true); -} let settings = require('Storage').readJSON('numerals.json',1); if (!settings) { settings = { color:0, drawMode:"fill", - menuButton:24 + menuButton:24, + showDate:0 }; } -function drawNum(num,col,x,y,func){ +function drawNum(num,col,x,y,func,funcName){ g.setColor(col); let tx = x*100+25; let ty = y*104+32; for (let i=0;i<numerals[num].length;i++){ - if (i>0) g.setColor((func==fill)?"#000000":col); - func(translate(tx,ty,numerals[num][i])); + g.setColor(col); + func(translate(tx,ty,numerals[num][i]), i>0); } } -function draw(drawMode){ +function draw(date){ let d = new Date(); - let h1 = Math.floor((_12hour?d.getHours()%12:d.getHours())/10); - let h2 = (_12hour?d.getHours()%12:d.getHours())%10; - let m1 = Math.floor(d.getMinutes()/10); - let m2 = d.getMinutes()%10; + let l1, l2; + if (date) { + setUpdateInt(0); + l1 = ("0"+(new Date()).getDate()).substr(-2); + l2 = ("0"+((new Date()).getMonth()+1)).substr(-2); + setTimeout(()=>{ draw(); setUpdateInt(1); }, 5000); + } else { + l1 = ("0"+(_12hour?d.getHours()%12:d.getHours())).substr(-2); + l2 = ("0"+d.getMinutes()).substr(-2); + } + var drawFunc = drawFuncs[settings.drawMode]; + if (drawFunc==undefined) drawFunc=drawFuncs.fill; g.clearRect(0,24,240,240); - drawNum(h1,_hCol[_rCol],0,0,eval(drawMode)); - drawNum(h2,_hCol[_rCol],1,0,eval(drawMode)); - drawNum(m1,_mCol[_rCol],0,1,eval(drawMode)); - drawNum(m2,_mCol[_rCol],1,1,eval(drawMode)); + drawNum(l1[0],_hCol[_rCol],0,0,drawFunc); + drawNum(l1[1],_hCol[_rCol],1,0,drawFunc); + drawNum(l2[0],_mCol[_rCol],0,1,drawFunc); + drawNum(l2[1],_mCol[_rCol],1,1,drawFunc); +} + +function setUpdateInt(set){ + if (interval) clearInterval(interval); + if (set) interval=setInterval(draw, REFRESH_RATE); } Bangle.setLCDMode(); - -clearWatch(); +g.reset().clear(); setWatch(Bangle.showLauncher, settings.menuButton, {repeat:false,edge:"falling"}); - -g.clear(); -clearInterval(); if (settings.color>0) _rCol=settings.color-1; -interval=setInterval(draw, REFRESH_RATE, settings.drawMode); -draw(settings.drawMode); +setUpdateInt(1); +draw(); +if (settings.showDate) { + Bangle.on('touch', () => draw(1)); +} Bangle.on('lcdPower', function(on){ if (on){ if (settings.color==0) _rCol = Math.floor(Math.random()*_hCol.length); - draw(settings.drawMode); - interval=setInterval(draw, REFRESH_RATE, settings.drawMode); - }else - { - clearInterval(interval); - } + draw(); + setUpdateInt(1); + } else setUpdateInt(0); }); Bangle.loadWidgets(); -Bangle.drawWidgets(); \ No newline at end of file +Bangle.drawWidgets(); diff --git a/apps/numerals/numerals.settings.js b/apps/numerals/numerals.settings.js index 2d388525c..991abc888 100644 --- a/apps/numerals/numerals.settings.js +++ b/apps/numerals/numerals.settings.js @@ -1,41 +1,49 @@ -(function(back) { - function updateSettings() { +(function(back) { + function updateSettings() { storage.write('numerals.json', numeralsSettings); - }; + } function resetSettings() { numeralsSettings = { color:0, drawMode:"fill", - menuButton:22 + menuButton:22, + showDate:0 }; updateSettings(); } let numeralsSettings = storage.readJSON('numerals.json',1); - if (!numeralsSettings) resetSettings(); - let dm = ["fill","frame"]; + if (!numeralsSettings) resetSettings(); + if (numeralsSettings.menuButton===undefined) numeralsSettings.menuButton=22; + let dm = ["fill","frame","framefill","thickframe"]; let col = ["rnd","r/g","y/w","o/c","b/y"]; let btn = [[24,"BTN1"],[22,"BTN2"],[23,"BTN3"],[11,"BTN4"],[16,"BTN5"]]; var menu={ - "" : { "title":"Numerals"}, - "Colors": { - value: 0|numeralsSettings.color, - min:0,max:4, - format: v=>col[v], - onchange: v=> { numeralsSettings.color=v; updateSettings();} + "" : { "title":"Numerals"}, + "Colors": { + value: 0|numeralsSettings.color, + min:0,max:col.length-1, + format: v=>col[v], + onchange: v=> { numeralsSettings.color=v; updateSettings();} }, - "Draw mode": { - value: 0|dm.indexOf(numeralsSettings.drawMode), - min:0,max:1, - format: v=>dm[v], - onchange: v=> { numeralsSettings.drawMode=dm[v]; updateSettings();} + "Draw": { + value: 0|dm.indexOf(numeralsSettings.drawMode), + min:0,max:dm.length-1, + format: v=>dm[v], + onchange: v=> { numeralsSettings.drawMode=dm[v]; updateSettings();} }, "Menu button": { - value: 1|btn[numeralsSettings.menuButton], - min:0,max:4, + value: btn.findIndex(e=>e[0]==numeralsSettings.menuButton), + min:0,max:btn.length-1, format: v=>btn[v][1], onchange: v=> { numeralsSettings.menuButton=btn[v][0]; updateSettings();} - }, + }, + "Date on touch": { + value: 0|numeralsSettings.showDate, + min:0,max:1, + format: v=>v?"On":"Off", + onchange: v=> { numeralsSettings.showDate=v; updateSettings();} + }, "< back": back }; E.showMenu(menu); -}) \ No newline at end of file +}) diff --git a/apps/openloc/ChangeLog b/apps/openloc/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/openloc/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/openseizure/ChangeLog b/apps/openseizure/ChangeLog new file mode 100644 index 000000000..4c21f3ace --- /dev/null +++ b/apps/openseizure/ChangeLog @@ -0,0 +1 @@ +0.01: New Widget! diff --git a/apps/openseizure/README.md b/apps/openseizure/README.md new file mode 100644 index 000000000..10a3a8a79 --- /dev/null +++ b/apps/openseizure/README.md @@ -0,0 +1,12 @@ +# OpenSeizureDetector Widget + +A widget to work alongside [OpenSeizureDetector](https://www.openseizuredetector.org.uk/) + +This is currently just a test and is not ready for everyday use. + +When the widget is running it puts the accelerometer into 25Hz mode, and then +roughly every second it outputs 20 samples (bytes) of acceleration data as a notification +on BLE Service `"a19585e9-0001-39d0-015f-b3e2b9a0c854"`, characteristic `"a19585e9-0002-39d0-015f-b3e2b9a0c854"`. + +Each byte is 1/25th of a second, with a magnitude of acceleration. It is scaled +such that 1g is 64. diff --git a/apps/openseizure/widget.js b/apps/openseizure/widget.js new file mode 100644 index 000000000..b8d8e34f1 --- /dev/null +++ b/apps/openseizure/widget.js @@ -0,0 +1,41 @@ +(() => { + function draw() { + g.reset(); + g.drawImage(E.toArrayBuffer(atob("GBiEBAAAAAABEREQAAAAAAAAAAAKmZkgAAAAAAAAAAAKmZkgAAAAAAAAAAAKkzkgAAAAAAACIQAKkzkgABIgAAAZmSAKPykgApmRAAApmZoqMjkiqZmSAAKZmZmZ8zmpmZmZIAKZmZmZMzmZmZmZIAEpmZmZkzqZmZmSEAACqZmZkjOZmZogAAAAApmZkjOZmSAAAAAAApmZn/mZmSAAAAACqZmZrymZmZogAAEpmZmZkzmZmZmSEAqZmZmZkjqZmZmZoAKZmZmamvmpmZmZIAApmZIan6mhKZmSAAAZmiAKkymgAqmRAAACIAAKkimgAAIgAAAAAAAKkimgAAAAAAAAAAAKmZmgAAAAAAAAAAAKmZmgAAAAAAAAAAABEREQAAAAAA==")), this.x, this.y); + } + + var accelData = new Uint8Array(20); + var accelIdx = 0; + //http://kionixfs.kionix.com/en/datasheet/KX023-1025%20Specifications%20Rev%2012.0.pdf + Bangle.accelWr(0x1B,0x01 | 0x40); // 25hz output, ODR/2 filter + Bangle.setPollInterval(40); // 25hz input + Bangle.on('accel',function(a) { + accelData[accelIdx++] = E.clip(a.mag*64,0,255); + if (accelIdx>=accelData.length) { + accelIdx = 0; + try { NRF.updateServices({ + "a19585e9-0001-39d0-015f-b3e2b9a0c854" : { + "a19585e9-0002-39d0-015f-b3e2b9a0c854" : { + value : accelData, notify : true + } + } + })} catch(e) {} + } + }); + + NRF.setServices({ + "a19585e9-0001-39d0-015f-b3e2b9a0c854" : { + "a19585e9-0002-39d0-015f-b3e2b9a0c854" : { + value : accelData, + maxLen : 20, + readable : true, + notify : true + } + } + }); + + // add your widget + WIDGETS["openseizure"]={ + area:"tl", width: 24, draw:draw + }; +})() diff --git a/apps/openseizure/widget.png b/apps/openseizure/widget.png new file mode 100644 index 000000000..9c0ecb772 Binary files /dev/null and b/apps/openseizure/widget.png differ diff --git a/apps/openstmap/ChangeLog b/apps/openstmap/ChangeLog index 2d60cb688..a7b8065fa 100644 --- a/apps/openstmap/ChangeLog +++ b/apps/openstmap/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Fix marker position, color, and map scaling +0.03: Show widgets (mainly so we can use the GPS recorder widget) diff --git a/apps/openstmap/app.js b/apps/openstmap/app.js index ae4817f16..5be4be82a 100644 --- a/apps/openstmap/app.js +++ b/apps/openstmap/app.js @@ -1,11 +1,12 @@ var s = require("Storage"); var map = s.readJSON("openstmap.json"); +var HASWIDGETS = true; +var y1,y2; map.center = Bangle.project({lat:map.lat,lon:map.lon}); var lat = map.lat, lon = map.lon; var fix = {}; - function redraw() { var cx = g.getWidth()/2; var cy = g.getHeight()/2; @@ -17,6 +18,7 @@ function redraw() { var ty = 0|(iy/map.tilesize); var ox = (tx*map.tilesize)-ix; var oy = (ty*map.tilesize)-iy; + g.setClipRect(0,y1,g.getWidth()-1,y2); for (var x=ox,ttx=tx;x<g.getWidth();x+=map.tilesize,ttx++) { for (var y=oy,tty=ty;y<g.getHeight();y+=map.tilesize,tty++) { var img = s.read("openstmap-"+ttx+"-"+tty+".img"); @@ -29,6 +31,7 @@ function redraw() { } } drawMarker(); + g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); } function drawMarker() { @@ -43,9 +46,6 @@ function drawMarker() { g.fillRect(ix-2,iy-2,ix+2,iy+2); } -redraw(); - - var fix; Bangle.on('GPS',function(f) { fix=f; @@ -60,6 +60,18 @@ Bangle.on('GPS',function(f) { drawMarker(); }); Bangle.setGPSPower(1); + +if (HASWIDGETS) { + Bangle.loadWidgets(); + Bangle.drawWidgets(); + y1 = 24; + var hasBottomRow = Object.keys(WIDGETS).some(w=>WIDGETS[w].area[0]=="b"); + y2 = g.getHeight() - (hasBottomRow ? 24 : 1); +} else { + y1=0; + y2=g.getHeight()-1; +} + redraw(); setWatch(function() { diff --git a/apps/openstmap/custom.html b/apps/openstmap/custom.html index 50d6149cb..81a55a4f8 100644 --- a/apps/openstmap/custom.html +++ b/apps/openstmap/custom.html @@ -38,11 +38,11 @@ <button id="cancel" class="btn">Cancel</button></div> </div> - <script src="../../lib/customize.js"></script> + <script src="../../core/lib/customize.js"></script> <script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet.js"></script> <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> - <script src="https://espruino.github.io/EspruinoWebTools/heatshrink.js"></script> - <script src="https://espruino.github.io/EspruinoWebTools/imageconverter.js"></script> + <script src="../../core/lib/heatshrink.js"></script> + <script src="../../core/lib/imageconverter.js"></script> <script> /* @@ -146,9 +146,6 @@ TODO: lat : centerlatlon.lat, lon : centerlatlon.lng })}); - mapFiles.unshift({"name":"openstmap.app.js","url":"app.js"}); - mapFiles.unshift({"name":"openstmap.img","url":"app-icon.js","evaluate":true}); - console.log(mapFiles); }); }); diff --git a/apps/osgridref/ChangeLog b/apps/osgridref/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/osgridref/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/osgridref/app-icon.js b/apps/osgridref/app-icon.js new file mode 100644 index 000000000..7feae2678 --- /dev/null +++ b/apps/osgridref/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwghC/AH4A/AGmqAAWgBQtc3cQAQIWKDA0F5YXBgEL3gWE0AXFDAlcjYXCAAOwAYUKC4MKC4gLCgO7rYXEJIYnBC4wgBIIO75gXELosKC4geBC4MM3e13dQCwoUCFAIYDMwQNBOQNcC4xECAIYVBHAWghijBUhAVCJAZEBAYfAgFbiEFIwgXECQSWCC4aQBiHMgBKCC4ZGDVwZgCiBHBAQMb4oXELQTbBF4gIBgsRiMQje15cRC4K/DXYhfEhnFqobB2J9BBgQkBJIhNFC4PMqBjB1kbC5o8Bhe1F4Ox5YEBiAQCC45jBa4W72MQJAKQB2CjCC5BsCgsbR4JEBoEA2qJCRQIUCbAgwCgMbU4OwbQJ4CUYYEBVYSUEAATCB5kL3gkCFAQADRwQXF5YYB5YXDXIZGCTIYAEPYQaBOgR3DCwIECFwrDB3e8hewFgQXDRYQXIqpHBgAXCTgJcFIwfLC4ewC4JeBAARZDbwbWD4APC3gXBFwQACOgpFErdQU4UMJ4oYCC4RcG5fBC4OwFwoA/AH4A/AH4AEA")) diff --git a/apps/osgridref/app.js b/apps/osgridref/app.js new file mode 100644 index 000000000..6681fd85b --- /dev/null +++ b/apps/osgridref/app.js @@ -0,0 +1,89 @@ +function getLogo() { + return require("heatshrink").decompress(atob("mUcggHE1QADCY3L3cA5gCBAAoXEDI0M3YVChe8BYmgDAwZE4AYDAAOwAYUKDAMKC4mgBgUL2AYFAgYQBDA4yC3e8MYRhIhQYFAoJ6DhYYHCoQRCDApMC3fA5gwHDAxqBG4R7BGQJ3DDA8KGIY7BAYUMO4pJDDAgXDQQYYBhmw5bgBDBY6EMgMLPYIxBQAPADAimDDYIhDPogYC3hOCLwT5D0ASCDAhIBcobMCCgYRDVwg6ChnLMIPA3cMDAgqEfIgxCCIIzB2BLBToIYMKAW7JYSYC4GwH4YYGJYJfCLoLHFDAIVBMY5hCSowWBgG8BYI/CCoY5EFYcLDAIXBPoYaCAgTNBAQQYEGgfMhYxBOIYwEJoRkDM4vLDAYJBDAj4FJghLBcIRYCCQRhCPogAEMAO8fgIuCDAg2EDAz5BS4YWBCQZgDJIUMB4TDCDAJiBAAT1FZwQLCCAm8DAIgEGIZNFDI27hhTGDIQYCPA28FgIvBGAQ")); +} + +g.clear(1); +g.drawImage(getLogo(),g.getWidth()-50, g.getHeight()-(28+24)); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +function onGPS(fix) { + var os = {northing:"---", easting:"---"} + var state = ""; + if (fix.fix) { + os = OsGridRef.latLongToOsGrid(fix); + state = "GPS Fix"; + } else { + state = "No Fix "; + } + var y = 30, h=48, d1 = 18, d2 = 80; + g.reset(); + g.setFont("6x8",2).setFontAlign(-1,-1); + g.drawString("Northing", 10,y); + g.drawString("Easting", 10,y+d2); + g.drawString(state,10,g.getHeight()-48,true/*erase bg*/) + g.setFont("6x8",1); + g.drawString(fix.satellites+" Satellites ",10,g.getHeight()-32,true/*erase bg*/) + g.setFont("Vector",h).setFontAlign(1,-1); + g.clearRect(0,y+d1,g.getWidth()-1,y+d1+h); + g.drawString(os.northing, g.getWidth()-1,y+d1); + g.clearRect(0,y+d1+d2,g.getWidth()-1,y+d1+d2+h); + g.drawString(os.easting, g.getWidth()-1,y+d1+d2); +} + +Bangle.setGPSPower(1); +Bangle.on('GPS', onGPS); + +Number.prototype.toRad = function() { return this*Math.PI/180; }; +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +/* Ordnance Survey Grid Reference functions (c) Chris Veness 2005-2014 */ +/* - www.movable-type.co.uk/scripts/gridref.js */ +/* - www.movable-type.co.uk/scripts/latlon-gridref.html */ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +function OsGridRef(easting, northing) { + this.easting = 0|easting; + this.northing = 0|northing; +} +OsGridRef.latLongToOsGrid = function(point) { + var lat = point.lat.toRad(); + var lon = point.lon.toRad(); + + var a = 6377563.396, b = 6356256.909; // Airy 1830 major & minor semi-axes + var F0 = 0.9996012717; // NatGrid scale factor on central meridian + var lat0 = (49).toRad(), lon0 = (-2).toRad(); // NatGrid true origin is 49�N,2�W + var N0 = -100000, E0 = 400000; // northing & easting of true origin, metres + var e2 = 1 - (b*b)/(a*a); // eccentricity squared + var n = (a-b)/(a+b), n2 = n*n, n3 = n*n*n; + + var cosLat = Math.cos(lat), sinLat = Math.sin(lat); + var nu = a*F0/Math.sqrt(1-e2*sinLat*sinLat); // transverse radius of curvature + var rho = a*F0*(1-e2)/Math.pow(1-e2*sinLat*sinLat, 1.5); // meridional radius of curvature + var eta2 = nu/rho-1; + + var Ma = (1 + n + (5/4)*n2 + (5/4)*n3) * (lat-lat0); + var Mb = (3*n + 3*n*n + (21/8)*n3) * Math.sin(lat-lat0) * Math.cos(lat+lat0); + var Mc = ((15/8)*n2 + (15/8)*n3) * Math.sin(2*(lat-lat0)) * Math.cos(2*(lat+lat0)); + var Md = (35/24)*n3 * Math.sin(3*(lat-lat0)) * Math.cos(3*(lat+lat0)); + var M = b * F0 * (Ma - Mb + Mc - Md); // meridional arc + + var cos3lat = cosLat*cosLat*cosLat; + var cos5lat = cos3lat*cosLat*cosLat; + var tan2lat = Math.tan(lat)*Math.tan(lat); + var tan4lat = tan2lat*tan2lat; + + var I = M + N0; + var II = (nu/2)*sinLat*cosLat; + var III = (nu/24)*sinLat*cos3lat*(5-tan2lat+9*eta2); + var IIIA = (nu/720)*sinLat*cos5lat*(61-58*tan2lat+tan4lat); + var IV = nu*cosLat; + var V = (nu/6)*cos3lat*(nu/rho-tan2lat); + var VI = (nu/120) * cos5lat * (5 - 18*tan2lat + tan4lat + 14*eta2 - 58*tan2lat*eta2); + + var dLon = lon-lon0; + var dLon2 = dLon*dLon, dLon3 = dLon2*dLon, dLon4 = dLon3*dLon, dLon5 = dLon4*dLon, dLon6 = dLon5*dLon; + + var N = I + II*dLon2 + III*dLon4 + IIIA*dLon6; + var E = E0 + IV*dLon + V*dLon3 + VI*dLon5; + + return new OsGridRef(E, N); +}; diff --git a/apps/osgridref/app.png b/apps/osgridref/app.png new file mode 100644 index 000000000..2b85ddb09 Binary files /dev/null and b/apps/osgridref/app.png differ diff --git a/apps/osmpoi/ChangeLog b/apps/osmpoi/ChangeLog new file mode 100644 index 000000000..1c066f451 --- /dev/null +++ b/apps/osmpoi/ChangeLog @@ -0,0 +1,3 @@ +0.01: New App! +0.02: Change img when no fix +0.03: Add HTML class for Spectre.CSS diff --git a/apps/osmpoi/README.md b/apps/osmpoi/README.md new file mode 100644 index 000000000..01e77dd86 --- /dev/null +++ b/apps/osmpoi/README.md @@ -0,0 +1,9 @@ +# Points Of Interest Compass + +## Description + +Uploads all the points of interest in an area onto your watch, same as Beer Compass with more p.o.i. + +## Requests + +If you have any bug or feature request, please contact [Renaudgweb](https://github.com/renaudgweb/) diff --git a/apps/osmpoi/app-icon.js b/apps/osmpoi/app-icon.js new file mode 100644 index 000000000..a2baf9e9e --- /dev/null +++ b/apps/osmpoi/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A0PgYurg9kr0rGM4nBg9dsgADmUHGUYtHAAddGIJcgFpIxEMTsAlYtMAAZiaLh4AFmQwXLiSTaLiosBnMymUrGCYTBAAgvPCgjwaMh4raF/4v/F/4vUg4vulZgDgAAIF8EyEQUAh0cAAkVisHGA4+HF6gVBiwwFjkONo0HAAMOAAIvTnIhEiovMFQQADNgYvQroUDg4uGjj9EF448DF6a+HAAS+EF5CQCF6SMIeAQvFXYYwHF59eLpSOBF4hgKGAIvPskAFxKOFF80VM4KOFSBs5F6EWRY4xBF43+F5UyF6DuEizZBKwIuHSBQvXdIwvKMYsHlYvQW4IuPYAYRBMggvRgIvCFxwwCTYZlEg4vPlcHjkVFx6WJF6YuXMoTwCF58yVgIvXY4YvQrqqDGDAvvPYIvPsguaYQYv/F7owBF/4vfg4AGTIIAHF7gA/AH4AwA=")) diff --git a/apps/osmpoi/app.png b/apps/osmpoi/app.png new file mode 100644 index 000000000..31f09b531 Binary files /dev/null and b/apps/osmpoi/app.png differ diff --git a/apps/osmpoi/custom.html b/apps/osmpoi/custom.html new file mode 100644 index 000000000..6e61b68ee --- /dev/null +++ b/apps/osmpoi/custom.html @@ -0,0 +1,226 @@ +<html> + <head> + <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.3/dist/leaflet.css" /> + <link rel="stylesheet" href="../../css/spectre.min.css"> + </head> + <style> + body { + padding: 0; + margin: 0; + } + html, body, #map { + height: 100%; + width: 100%; + } + #map { z-index: 1; } + #controls { + padding: 10px; + margin: 10px; + border: 1px solid black; + position:absolute; + right:0px;top:0px; + background-color: rgb(255, 255, 255); + z-index: 100; + } + </style> + </head> + <body> + <div id="map"> + </div> + + <div id="controls" class="form-group"> + <select id="amenity" class="form-select select-lg"> + <option value="drinking_water">Drinking Water</option> + <option value="bicycle_parking">Bicycle Park</option> + <option value="post_box">Post Box</option> + <option value="bar">Bars</option> + <option value="bbq">Barbecue</option> + <option value="cafe">Café</option> + <option value="fast_food">Fast food</option> + <option value="restaurant">Restaurant</option> + <option value="bicycle_repair_station">Bicycle Repair</option> + <option value="bicycle_rental">Bicycle rental</option> + <option value="bus_station">Bus station</option> + <option value="atm">Bank</option> + <option value="pharmacy">Pharmacy</option> + <option value="interner_cafe">Cybercafé</option> + </select> + <p>Click <button id="poi" class="btn btn-primary">Find P.O.I.</button></p> + <p>If ok, Click <button id="upload" class="btn btn-primary">Upload</button></p> + </div> + + <script src="../../core/lib/customize.js"></script> + <script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet.js"></script> + <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> + <script src="https://unpkg.com/osmtogeojson@2.2.12/osmtogeojson.js"></script> + + <script> + /* + + https://overpass-turbo.eu/ to check queries. + Run: + + node + ({{bbox}}); + out; + + Over the area you're interested in, click on the POI and find out + what you need to search for, eg. + + node + [amenity=pub] + ({{bbox}}); + out; + +*/ + + var map = L.map('map').locate({setView: true, maxZoom: 16}); + var features = []; + L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 18, + attribution: 'Map data © <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors</a>' + }).addTo(map); + function buildOverpassApiUrl(map, overpassQuery) { + var bounds = map.getBounds().getSouth() + ',' + map.getBounds().getWest() + ',' + map.getBounds().getNorth() + ',' + map.getBounds().getEast(); + var nodeQuery = 'node[' + overpassQuery + '](' + bounds + ');'; + var wayQuery = 'way[' + overpassQuery + '](' + bounds + ');'; + var relationQuery = 'relation[' + overpassQuery + '](' + bounds + ');'; + var query = '?data=[out:json][timeout:15];(' + nodeQuery + wayQuery + relationQuery + ');out body geom;'; + var baseUrl = 'https://overpass-api.de/api/interpreter'; + var resultUrl = baseUrl + query; + return resultUrl; + } + + document.getElementById("poi").addEventListener("click", function() { + //var overpassApiUrl = buildOverpassApiUrl(map, "highway=bus_stop"); + var poi = document.getElementById("amenity").options[document.getElementById("amenity").selectedIndex].value; + var overpassApiUrl = buildOverpassApiUrl(map, "amenity="+poi); + var req = new XMLHttpRequest(); + req.responseType = 'json'; + req.onreadystatechange = function() { + console.log("XMLHttpRequest", this.readyState); + if (this.readyState == 4) { + var osmDataAsJson = req.response; + features = []; + if (osmDataAsJson.elements) { + osmDataAsJson.elements.forEach(function(el) { + if (el.type!="node") return; + features.push({lat:el.lat, lon:el.lon,name:el.tags.name}); + }); + } + + var resultAsGeojson = osmtogeojson(osmDataAsJson); + var resultLayer = L.geoJson(resultAsGeojson, { + style: function (feature) { + return {color: "#ff0000"}; + }, + filter: function (feature, layer) { + var isPolygon = (feature.geometry) && (feature.geometry.type !== undefined) && (feature.geometry.type === "Polygon"); + if (isPolygon) { + feature.geometry.type = "Point"; + var polygonCenter = L.latLngBounds(feature.geometry.coordinates[0]).getCenter(); + feature.geometry.coordinates = [ polygonCenter.lat, polygonCenter.lng ]; + } + return true; + }, + onEachFeature: function (feature, layer) { + var popupContent = ""; + popupContent = popupContent + "<dt>@id</dt><dd>" + feature.properties.type + "/" + feature.properties.id + "</dd>"; + var keys = Object.keys(feature.properties.tags); + keys.forEach(function (key) { + popupContent = popupContent + "<dt>" + key + "</dt><dd>" + feature.properties.tags[key] + "</dd>"; + }); + popupContent = popupContent + "</dl>" + layer.bindPopup(popupContent); + } + }).addTo(map); + } + }; + req.open("GET", overpassApiUrl, true); + req.send(); + }); + document.getElementById("upload").addEventListener("click", function() { + var app = `var features = ${JSON.stringify(features)}; +var img_nofix = require("heatshrink").decompress(atob("mEwhBC/AH4A/AH4A/AC2swMllcrBQoHBktWwIEBlYEBqwAEgAICF6FWldbrgDBAIMrFIIhBrlbAAIIBwOsAAgsClcxF6ErrmG2GGw1cqsxrmAwuG2OxxkxFoOCq1VFANVLgIyBPI4vLq2F2OwAAQrCAgPVw0xEgVVMoQ7BwsxmOm1iUCMCIuD2GM2AvC2IuDFQIACwADCrZrCGCOBqovI2NcEAIuBTwQAHlZhCL6FVYAKQG2NV1i3BZYIpDrZiFlb1BYSFWwAvG6tbwOCmIuFF4YAC2FVwOBMCFWraBCRwReDBYIpELQOAAQQ5CqpgBF57RBFYK+C2IcBw4vBEQIwDrYEDrlbGYOMmMr64vQd4hcBX4VcF4LsGOIYGCxhMBYAKORGAhhBF4TtBAAzvFwuAwIvPlbuBXIQAE2BMBHgIoBE4QvEricBqtWF4KPOF4KICAAReCd4WBdoYAJmKPCF50lrhYCYIuxreBwUxR5RrBrmCwIABF54pCFwrkBJoMxFAKGBF4lcFwNbR4JxBX6GGFYeHSoOGSQJgBGARVBFoIqCMIWMlS+ClbvRMIbFEJ4PXwMrmIqBAARjDleB67ABFxowCYAgDBQQVbFwIAB00xGAQMDA4OCNoJdOAAWBYAex6uGNAIcBFwSvB1mCq1VFYMxqwICA4IvRDgKKDw0qwQrBPgIuBX4IoCAAmBDILQCF6AwBwBgBFwgwCldVTQKJBqtcwB1BSgXV6uAXyAvCrYuHAAMrrYuBGIQABwoGBOgWxF6SEBFwWmFwpgBF4IADxgyC2IFCR6Z5BLpHX1krLoQADLYQHEqrvRWQMrFxKOEF4eMxgyBGgVWkovRgCMH1kqZIInBLwwtCRwZfQqxdLEYQuFAQYHCraORq2BXZPVKwIABEoIGBFoYCCRwNWRyIuIquGrgfBldWwGAwqMBFYVbrlcqovSL42sksrwCsBD4QDBkoyBqsxFQINBmItRL4UrGAZdBLIIABCQ8lgAsBH4IsSGA4uBDq4wTq0xmIuqAH4A/AH4A/AH4AHA=")); +var img_fix = require("heatshrink").decompress(atob("mEwhBC/AH4A/AH4A/AE0rg4vtq8PF1kHxM7gJesF4Jgrg+IF4M6MFReBF4JgqXoIvDMFJeCF4RgoLwYvDnZgmLwYvEMEpeEF4jBlmYvIMEheFF4pgjXogvGMEReGF407MEBeGF45gfg+IF5rBfLw4vHMDxeIF5BgdLxAvIMDkHFxAvJMDZeJF5JgaLxQvKnZgYLxQvLMC5eLF5bBXmYvWMCxeMF5hgVXpYvNMCheNF5s7MCReNF5xgRg+IFZNersylcHhEPmjBbLw1er1XlkHIhI0CnRgUmQqEKwKnRgIzBiBpBnUICpszryCCFiIyGM4TBRAH4A/AH4A/AH4AFA")); + +// https://github.com/Leaflet/Leaflet/blob/master/src/geo/projection/Projection.SphericalMercator.js +function project(latlong) { + var d = Math.PI / 180, + max = 85.0511287798, + R = 6378137, // earth radius in m + lat = Math.max(Math.min(max, latlong.lat), -max), + sin = Math.sin(lat * d); + return {x:R * latlong.lon * d, + y:R * Math.log((1 + sin) / (1 - sin)) / 2}; +} + +features.forEach(function(f) { + f.p = project(f); +}); +var fix = {fix:false,satellites:0}; +var nearest = undefined; +var nearestangle = 0; +var nearestdist = 0; + +Bangle.on('GPS', function(f) { + fix = f; + fix.p = project(fix); + nearest = undefined; + nearestangle = 0; + nearestdist = 5000; // 5km + features.forEach(function(f) { + var dx = f.p.x - fix.p.x; + var dy = f.p.y - fix.p.y; + var d = Math.sqrt(dx*dx + dy*dy); + if (d<nearestdist) { + nearestdist = d; + nearest = f; + } + }); + if (nearest) { + var dx = nearest.p.x - fix.p.x; + var dy = nearest.p.y - fix.p.y; + nearestangle = Math.atan2(dy,dx); + } +}); + +Bangle.on('mag', function(m) { + if (!Bangle.isLCDOn()) return; + var headingrad = m.heading*Math.PI/180; // in radians + if (!isFinite(headingrad)) headingrad=0; + if (nearest) + g.drawImage(img_fix,120,120,{ + rotate: (Math.PI/2)+headingrad-nearestangle, + scale:3, + }); + else + g.drawImage(img_nofix,120,120,{ + rotate: headingrad, + scale:2, + }); + g.clearRect(60,0,180,24); + g.setFontAlign(0,0); + g.setFont("6x8"); + if (fix.fix) { + g.drawString(nearest ? nearest.name : "---",120,4); + g.setFont("6x8",2); + g.drawString(nearest ? Math.round(nearestdist)+"m" : "---",120,16); + } else { + g.drawString(fix.satellites+" satellites",120,4); + } +}); +Bangle.setCompassPower(1); +Bangle.setGPSPower(1); +g.clear();`; + + sendCustomizedApp({ + storage:[ + {name:"osmpoi.app.js", url:"app.js", content:app} + ] + }); + }); + + </script> + </body> +</html> diff --git a/apps/pipboy/app.js b/apps/pipboy/app.js index a8539c7db..5f885d769 100644 --- a/apps/pipboy/app.js +++ b/apps/pipboy/app.js @@ -77,29 +77,29 @@ function boy() { } function drawClock() { - var t = new Date(); - var h = t.getHours(); - var m = t.getMinutes(); - var dd = t.getDate(); - var mm = t.getMonth()+1; //month is zero-based - var yy = t.getFullYear(); - var time = ("0" + h).substr(-2) + ":" + ("0" + m).substr(-2); + var t = new Date(); + var h = t.getHours(); + var m = t.getMinutes(); + var dd = t.getDate(); + var mm = t.getMonth()+1; //month is zero-based + var yy = t.getFullYear(); + var time = ("0" + h).substr(-2) + ":" + ("0" + m).substr(-2); - //create date string - if (dd.toString().length < 2) dd = '0' + dd; - if (mm.toString().length < 2) mm = '0' + mm; - var date = dd + "." + mm + "." + yy; + //create date string + if (dd.toString().length < 2) dd = '0' + dd; + if (mm.toString().length < 2) mm = '0' + mm; + var date = dd + "." + mm + "." + yy; - g.setFont("6x8",bigFont); - g.setColor(green); - g.setFontAlign(0, -1, 0); + g.setFont("6x8",bigFont); + g.setColor(green); + g.setFontAlign(0, -1, 0); - g.clearRect(0, 110, 150, 140); - g.drawString(time, 70, 110); + g.clearRect(0, 110, 150, 140); + g.drawString(time, 70, 110); - //draw date - g.setFont("6x8", tinyFont); - g.drawString(date, 67, 177); + //draw date + g.setFont("6x8", tinyFont); + g.drawString(date, 67, 177); } function drawAll() { diff --git a/apps/pizzatimer/ChangeLog b/apps/pizzatimer/ChangeLog new file mode 100644 index 000000000..3c3e41a33 --- /dev/null +++ b/apps/pizzatimer/ChangeLog @@ -0,0 +1 @@ +0.01: You can now time cooking a Pizza! \ No newline at end of file diff --git a/apps/pizzatimer/README.md b/apps/pizzatimer/README.md new file mode 100644 index 000000000..14f2e6bbb --- /dev/null +++ b/apps/pizzatimer/README.md @@ -0,0 +1 @@ +# Pizza Timer \ No newline at end of file diff --git a/apps/pizzatimer/app-icon.js b/apps/pizzatimer/app-icon.js new file mode 100644 index 000000000..936ef6e2a --- /dev/null +++ b/apps/pizzatimer/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkBiIA/AH4AwgCzUgEFqtVDIcQDpkQgtO9wACqAfCoAYKCwIVD93kCQMQgAcDAA8F73tqEAAAQXC6Fe8owIiFO9peBpvdAAIRBgvdHQIwIggKBhsNCoPUF4UEgtAp3gFxHlhsFgvQptAFAMQGoPUhpmCLoouB7tArvV7tVC4QEBAIPuC40O8hECAAVVIwXQKIPQC4xGB8FNotEgBBBXIMQhtAIwPQpx4FiBGCotFgFd7vQBQIUBF4NAhwIBLwpGC6ovCEwMAhvUqvVgsOSAsNRoJcCCwKlCgsNPoIXBCAJ2FLwJ2EgpeBGgKOBD4MEVAkQr3QaAIxCqgvBiFUNAMES4SQERwNA6tdBoPVhpeBCYVQQYKXBC4veNQMECIR2CAoUFoB/CC4vugoJBUgIABBgMQgtNoEFbQMA91RC4wAEgALCYoVQ6HQ7wvFOoYAB6DaBBoSMBBAMApxHGgC9BBgPUprbBB4RLBO4NNC4tVgqMBoHQYgQcBDAcAoFUR4tQhvQKoQuBroDBDAZLBKAYXCCoKzCJYKtBb4QHBGQYXEp3gC4XUVIYFBAQVQGYgACr3gCYVFAQJgCAwIKB6kEqAYFh3lU4JBCAQLDDUwNAH4IvFgnuhtF6FdCAJFDggGBgvuoAXFVANQC4NVhoxBqAUBPAVe9xfGPAKfBIgNNgsNhtVGAPVFwPlC40RhvkIgQqCLgQFBpw9BCwzHBKIKRFAANQIoIuIJAIwBgFUCodFgFd93tdggwGpwYBAAhEBIoIuIDAnu6lEolNCoIWNDAVUCYQAB6sACxoYCgEFqtQAgIVOAH4AC")) \ No newline at end of file diff --git a/apps/pizzatimer/app.js b/apps/pizzatimer/app.js new file mode 100644 index 000000000..54928c121 --- /dev/null +++ b/apps/pizzatimer/app.js @@ -0,0 +1,270 @@ +/* UI GLOBALS */ + +const HOUR_SCENE = 0; +const MIN_SCENE = 1; +const SEC_SCENE = 2; +const COUNTDOWN_SCENE = 3; + +var currentScene = 0; + +var btn1Watch; +var btn2Watch; +var btn3Watch; + +var drawInterval; + +/* STATE GLOBALS */ + +var menuTime = new Uint8Array([0,0,0]); +var countdownTime = menuTime.slice(0); +var show = [true, true, true]; + +/* COUNTDOWN CONSTANTS */ + +const HOUR_INDEX = 0; +const MIN_INDEX = 1; +const SEC_INDEX = 2; + +var flashIndex = HOUR_INDEX; + +/* logic */ + +function setCountdownTime() { + countdownTime = menuTime.slice(0); +} + +function countDownFinished() { + return countdownTime[HOUR_INDEX] <= 0 && + countdownTime[MIN_INDEX] <= 0 && + countdownTime[SEC_INDEX] <= 0; +} + +function alertCountdownFinished() { + if (drawInterval) return; + Bangle.buzz() + .then(() => new Promise(resolve => setTimeout(resolve, 200))) + .then(() => Bangle.buzz()); + setTimeout(alertCountdownFinished, 2000); +} + +function unsetDrawInterval() { + clearInterval(drawInterval); + drawInterval = undefined; +} + +function decrementCountdownTime() { + const allZero = countDownFinished(); + + if(allZero) { + return; + } + + if (countdownTime[SEC_INDEX] !== 0) { + countdownTime[SEC_INDEX] = countdownTime[SEC_INDEX] - 1; + return; + } + + countdownTime[SEC_INDEX] = 59; + + if (countdownTime[MIN_INDEX] !== 0) { + countdownTime[MIN_INDEX] = countdownTime[MIN_INDEX] - 1; + return; + } + + countdownTime[MIN_INDEX] = 59; + + if (countdownTime[HOUR_INDEX] !== 0) { + countdownTime[HOUR_INDEX] = countdownTime[HOUR_INDEX] - 1; + return; + } +} + +function toggleShow(timeIndex) { + show[timeIndex] = !show[timeIndex]; +} + +function twoPadded(i) { + return i.length < 2 ? "0" + i : i; +} + +function getTimeString(t) { + let hour = t[HOUR_INDEX].toString(); + let min = t[MIN_INDEX].toString(); + let sec = t[SEC_INDEX].toString(); + + hour = show[HOUR_INDEX] ? twoPadded(hour) : " "; + min = show[MIN_INDEX] ? twoPadded(min) : " "; + sec = show[SEC_INDEX] ? twoPadded(sec) : " "; + + return hour + ":" + min + ":" + sec; +} + +/* drawing */ + +/* + shamelessly stollen from Bluetooth Music Controls + https://github.com/espruino/BangleApps/blob/6b09377414e02d575b8335bb051c831ecc9da9d9/apps/hidmsic/hid-music.js#L42 +*/ +function drawArrows() { + function c(a) { + return { + width: 8, + height: a.length, + bpp: 1, + buffer: (new Uint8Array(a)).buffer + }; + } + const d = g.getWidth() - 18; + g.drawImage(c([16,56,124,254,16,16,16,16]),d,40); + g.drawImage(c([16,16,16,16,254,124,56,16]),d,194); + g.drawImage(c([0,8,12,14,255,14,12,8]),d,116); +} + +function drawTime(input) { + g.clear(); + g.setFontAlign(0,0); + g.setFont("4x6",5); + g.drawString(input, g.getWidth() / 2, g.getHeight() / 2); +} + +function drawMenu() { + const timeString = getTimeString(menuTime); + drawTime(timeString); + drawArrows(); +} + +function drawCountdown() { + const timeString = getTimeString(countdownTime); + drawTime(timeString); +} + +/* button callbacks */ + +function getMaxSelectableTime() { + return flashIndex === HOUR_INDEX ? 23 : 59; +} + +/* btn1 */ + +function incrementMenuTime() { + const maxTime = getMaxSelectableTime(); + const currentTime = menuTime[flashIndex]; + const newTime = currentTime < maxTime ? currentTime + 1 : 0; + menuTime[flashIndex] = newTime; +} + +/* btn2 */ + +function incrementScene() { + currentScene++; +} + +function incrementFlashIndex() { + flashIndex++; +} + +function showAll() { + for(var i = 0; i < show.length; i++) { + show[i] = true; + } +} + +function showFlashIndex() { + show[flashIndex] = true; +} + +function hideFlashIndex() { + show[flashIndex] = false; +} + +function next() { + incrementScene(); + + if (currentScene === COUNTDOWN_SCENE) { + showAll(); + startCountdownScene(); + } else { + showFlashIndex(); + incrementFlashIndex(); + hideFlashIndex(); + } +} + +/* btn3 */ + +function decrementMenuTime() { + const maxTime = getMaxSelectableTime(); + const currentTime = menuTime[flashIndex]; + const newTime = currentTime > 0 ? currentTime - 1 : maxTime; + menuTime[flashIndex] = newTime; +} + +/* watches */ + +function setupMenuWatches() { + clearWatch(); + btn1Watch = setWatch(incrementMenuTime, BTN1, {repeat: true}); + btn2Watch = setWatch(next, BTN2, {repeat: true}); + btn3Watch = setWatch(decrementMenuTime, BTN3, {repeat: true}); +} + +function setupCountdownWatches() { + clearWatch(); + btn2Watch = setWatch(main, BTN2, {repeat: true}); +} + +/* scenes */ + +function menu() { + drawMenu(); + toggleShow(flashIndex); +} + +function countdown() { + decrementCountdownTime(); + drawCountdown(); + + if (countDownFinished()) { + unsetDrawInterval(); + alertCountdownFinished(); + } +} + +/* init */ + +function unsetDrawInterval() { + if (!drawInterval) return; + clearInterval(drawInterval); + drawInterval = undefined; +} + +function startMenuScene() { + setupMenuWatches(); + unsetDrawInterval(); + menu(); + drawInterval = setInterval(menu, 500); +} + +function startCountdownScene() { + setupCountdownWatches(); + unsetDrawInterval(); + setCountdownTime(); + showAll(); + drawCountdown(); + drawInterval = setInterval(countdown, 1000); +} + +/* main */ + +function reset() { + currentScene = 0; + flashIndex = HOUR_INDEX; + hideFlashIndex(); +} + +function main() { + reset(); + startMenuScene(); +} + +main(); diff --git a/apps/pizzatimer/pizza.png b/apps/pizzatimer/pizza.png new file mode 100644 index 000000000..d5a083633 Binary files /dev/null and b/apps/pizzatimer/pizza.png differ diff --git a/apps/pomodo/ChangeLog b/apps/pomodo/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/pomodo/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/pomodo/pomodoro.js b/apps/pomodo/pomodoro.js index 013828d12..3e11739da 100644 --- a/apps/pomodo/pomodoro.js +++ b/apps/pomodo/pomodoro.js @@ -3,254 +3,254 @@ const storage = require("Storage"); const DEFAULT_TIME = 1500; // 25m const TIME_BREAK = 300; const STATES = { - INIT: 1, - STARTED: 2, - DONE: 3, - BREAK: 4 + INIT: 1, + STARTED: 2, + DONE: 3, + BREAK: 4 }; var counterInterval; class State { - constructor (state) { - this.state = state; - this.next = null; + constructor (state) { + this.state = state; + this.next = null; + } + + setNext (next) { + this.next = next; + } + + setButtons () {} + + clear () { + clearWatch(); + g.clear(); + g.setFontAlign(0, 0); + } + + draw () { + g.clear(); + } + + init () { } + + go (nextState) { + if (nextState) { + this.next = nextState; } - setNext (next) { - this.next = next; - } - - setButtons () {} - - clear () { - clearWatch(); - g.clear(); - g.setFontAlign(0, 0); - } - - draw () { - g.clear(); - } - - init () { } - - go (nextState) { - if (nextState) { - this.next = nextState; - } - - this.clear(); - this.init(); - this.setButtons(); - this.draw(); - } + this.clear(); + this.init(); + this.setButtons(); + this.draw(); + } } class InitState extends State { - constructor (time) { - super(STATES.INIT); + constructor (time) { + super(STATES.INIT); - this.timeCounter = parseInt(storage.read(".pomodo") || DEFAULT_TIME, 10); - } + this.timeCounter = parseInt(storage.read(".pomodo") || DEFAULT_TIME, 10); + } - saveTime () { - storage.write('.pomodo', '' + this.timeCounter); - } + saveTime () { + storage.write('.pomodo', '' + this.timeCounter); + } - setButtons () { - setWatch(() => { - if (this.timeCounter + 300 > 3599) { - this.timeCounter = 3599; - } else { - this.timeCounter += 300; - } + setButtons () { + setWatch(() => { + if (this.timeCounter + 300 > 3599) { + this.timeCounter = 3599; + } else { + this.timeCounter += 300; + } - this.draw(); + this.draw(); - }, BTN1, { repeat: true }); + }, BTN1, { repeat: true }); - setWatch(() => { - if (this.timeCounter - 300 > 0) { - this.timeCounter -= 300; - this.draw(); - } - }, BTN3, { repeat: true }); + setWatch(() => { + if (this.timeCounter - 300 > 0) { + this.timeCounter -= 300; + this.draw(); + } + }, BTN3, { repeat: true }); - setWatch(() => { - if (this.timeCounter - 60 > 0) { - this.timeCounter -= 60; - this.draw(); - } - }, BTN4, { repeat: true }); + setWatch(() => { + if (this.timeCounter - 60 > 0) { + this.timeCounter -= 60; + this.draw(); + } + }, BTN4, { repeat: true }); - setWatch(() => { - if (this.timeCounter + 60 > 3599) { - this.timeCounter = 3599; - } else { - this.timeCounter += 60; - } + setWatch(() => { + if (this.timeCounter + 60 > 3599) { + this.timeCounter = 3599; + } else { + this.timeCounter += 60; + } - this.draw(); + this.draw(); - }, BTN5, { repeat: true }); + }, BTN5, { repeat: true }); - setWatch(() => { - this.saveTime(); - const startedState = new StartedState(this.timeCounter); + setWatch(() => { + this.saveTime(); + const startedState = new StartedState(this.timeCounter); - this.setNext(startedState); - this.next.go(); - }, BTN2, { repeat: true }); - } + this.setNext(startedState); + this.next.go(); + }, BTN2, { repeat: true }); + } - draw () { - g.clear(); - g.setFontAlign(0, 0); // center font - g.setFont("Vector", 50); // vector font, 80px - drawCounter(this.timeCounter); - } + draw () { + g.clear(); + g.setFontAlign(0, 0); // center font + g.setFont("Vector", 50); // vector font, 80px + drawCounter(this.timeCounter); + } } class StartedState extends State { - constructor (timeCounter) { - super(STATES.STARTED); + constructor (timeCounter) { + super(STATES.STARTED); - this.timeCounter = timeCounter; + this.timeCounter = timeCounter; + } + + draw () { + drawCounter(this.timeCounter, 120, 120); + } + + init () { + function countDown () { + this.timeCounter--; + + // Out of time + if (this.timeCounter <= 0) { + clearInterval(counterInterval); + counterInterval = undefined; + this.next.go(); + return; + } + + this.draw(); } - draw () { - drawCounter(this.timeCounter, 120, 120); - } - - init () { - function countDown () { - this.timeCounter--; - - // Out of time - if (this.timeCounter <= 0) { - clearInterval(counterInterval); - counterInterval = undefined; - this.next.go(); - return; - } - - this.draw(); - } - - const doneState = new DoneState(); - this.setNext(doneState); - counterInterval = setInterval(countDown.bind(this), 1000); - } + const doneState = new DoneState(); + this.setNext(doneState); + counterInterval = setInterval(countDown.bind(this), 1000); + } } class BreakState extends State { - constructor () { - super(STATES.BREAK); - } + constructor () { + super(STATES.BREAK); + } - draw () { - g.setFontAlign(0, 0); - } + draw () { + g.setFontAlign(0, 0); + } - init () { - const startedState = new StartedState(TIME_BREAK); + init () { + const startedState = new StartedState(TIME_BREAK); - this.setNext(startedState); - this.next.go(); - } + this.setNext(startedState); + this.next.go(); + } } class DoneState extends State { - constructor () { - super(STATES.DONE); + constructor () { + super(STATES.DONE); + } + + setButtons () { + setWatch(() => { + const initState = new InitState(); + clearTimeout(this.timeout); + initState.go(); + }, BTN1, { repeat: true }); + + setWatch(() => { + const breakState = new BreakState(); + clearTimeout(this.timeout); + breakState.go(); + }, BTN3, { repeat: true }); + + setWatch(() => { + }, BTN2, { repeat: true }); + } + + draw () { + g.clear(); + g.setFont("6x8", 2); + g.setFontAlign(0, 0, 3); + g.drawString("AGAIN", 230, 50); + g.drawString("BREAK", 230, 190); + g.setFont("Vector", 45); + g.setFontAlign(-1, -1); + + g.drawString('You\nare\na\nhero!', 50, 40); + } + + init () { + + function buzz () { + Bangle.buzz(); + Bangle.beep(200, 4000) + .then(() => new Promise(resolve => setTimeout(resolve, 50))) + .then(() => Bangle.beep(200, 3000)) + .then(() => new Promise(resolve => setTimeout(resolve, 200))) + .then(() => Bangle.beep(200, 3000)) + .then(() => new Promise(resolve => setTimeout(resolve, 300))) + .then(() => { + Bangle.beep(200, 3000); + Bangle.buzz() + }); } - setButtons () { - setWatch(() => { - const initState = new InitState(); - clearTimeout(this.timeout); - initState.go(); - }, BTN1, { repeat: true }); - - setWatch(() => { - const breakState = new BreakState(); - clearTimeout(this.timeout); - breakState.go(); - }, BTN3, { repeat: true }); - - setWatch(() => { - }, BTN2, { repeat: true }); - } - - draw () { - g.clear(); - g.setFont("6x8", 2); - g.setFontAlign(0, 0, 3); - g.drawString("AGAIN", 230, 50); - g.drawString("BREAK", 230, 190); - g.setFont("Vector", 45); - g.setFontAlign(-1, -1); - - g.drawString('You\nare\na\nhero!', 50, 40); - } - - init () { - - function buzz () { - Bangle.buzz(); - Bangle.beep(200, 4000) - .then(() => new Promise(resolve => setTimeout(resolve, 50))) - .then(() => Bangle.beep(200, 3000)) - .then(() => new Promise(resolve => setTimeout(resolve, 200))) - .then(() => Bangle.beep(200, 3000)) - .then(() => new Promise(resolve => setTimeout(resolve, 300))) - .then(() => { - Bangle.beep(200, 3000); - Bangle.buzz() - }); - } - - buzz(); - // again, 10 secs later - this.timeout = setTimeout(buzz.bind(this), 10000); - } + buzz(); + // again, 10 secs later + this.timeout = setTimeout(buzz.bind(this), 10000); + } } function drawCounter (currentValue, x, y) { - if (currentValue < 0) { - return; - } + if (currentValue < 0) { + return; + } - x = x || 120; - y = y || 120; + x = x || 120; + y = y || 120; - let minutes = 0; - let seconds = 0; + let minutes = 0; + let seconds = 0; - if (currentValue >= 60) { - minutes = Math.floor(currentValue / 60); - seconds = currentValue % 60; - } else { - seconds = currentValue; - } + if (currentValue >= 60) { + minutes = Math.floor(currentValue / 60); + seconds = currentValue % 60; + } else { + seconds = currentValue; + } - let minutesString = '' + minutes; - let secondsString = '' + seconds; + let minutesString = '' + minutes; + let secondsString = '' + seconds; - if (minutes < 10) { - minutesString = '0' + minutes; - } + if (minutes < 10) { + minutesString = '0' + minutes; + } - if (seconds < 10) { - secondsString = '0' + seconds; - } + if (seconds < 10) { + secondsString = '0' + seconds; + } - g.clear(); - g.drawString(minutesString + ':' + secondsString, x, y); + g.clear(); + g.drawString(minutesString + ':' + secondsString, x, y); } function init () { - const initState = new InitState(); - initState.go(); + const initState = new InitState(); + initState.go(); } init(); diff --git a/apps/pong/ChangeLog b/apps/pong/ChangeLog new file mode 100644 index 000000000..198d7bbde --- /dev/null +++ b/apps/pong/ChangeLog @@ -0,0 +1,3 @@ +0.01: New App! +0.02: 2 players local + improve ai +0.03: Keep display on during gameplay diff --git a/apps/pong/README.md b/apps/pong/README.md new file mode 100644 index 000000000..ea4939539 --- /dev/null +++ b/apps/pong/README.md @@ -0,0 +1,28 @@ +# Pong + +A clone of the Atari game Pong + +<img src="https://user-images.githubusercontent.com/702227/79855656-2a507a00-83c3-11ea-9162-65732729b992.png" height="384" width="384" /> + +## Features + +- Play against a dumb AI +- Play local Multiplayer against your friends + +## Controls + +Player's controls: +- UP: BTN1 +- DOWN: BTN2 +long press to move faster + +Restart a game: +- RESET: BTN3 + +Buttons for player 2: +- UP: BTN4 +- DOWN: BTN5 + +## Creator + +<https://twitter.com/fredericrous> diff --git a/apps/pong/app-icon.js b/apps/pong/app-icon.js new file mode 100644 index 000000000..881e60ba9 --- /dev/null +++ b/apps/pong/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgIEBgOABQYFD8AUEApoXFDqIXV4BYGKZIANsIRE+IFE/IFEvCIFGrgXLDqIAOgc/9/2hv+g8///3AoUwvE3xuABYP4m3NzwFB7E2tu/CIMYm09wYFDjoFCj4pB/8HkEP+EBFII7EAosDJxYA=")) diff --git a/apps/pong/app.js b/apps/pong/app.js new file mode 100644 index 000000000..012cd8f81 --- /dev/null +++ b/apps/pong/app.js @@ -0,0 +1,425 @@ +/** + * BangleJS Pong game + * + * Original Author: Frederic Rousseau https://github.com/fredericrous + * Created: April 2020 + * + * Inspired by: + * - Let's make pong, One Man Army Studios, Youtube + * - Pong.js, KanoComputing, Github + * - Coding Challenge #67: Pong!, The Coding Train, Youtube + * - Pixl.js Multiplayer Pong, espruino website + */ + +const SCREEN_WIDTH = 240; +const FPS = 16; +const MAX_SCORE = 11; +let scores = [0, 0]; +let aiSpeedRandom = 0; +let winnerMessage = ''; + +const sound = { + ping: () => Bangle.beep(8, 466), + pong: () => Bangle.beep(8, 220), + fall: () => Bangle.beep(16*3, 494).then(_ => Bangle.beep(32*3, 3322)) +}; + +function Vector(x, y) { + this.x = x; + this.y = y; +} +Vector.prototype.add = function (x) { + this.x += x.x || 0; + this.y += x.y || 0; + return this; +}; + +const constrain = (n, low, high) => Math.max(Math.min(n, high), low); +const random = (min, max) => Math.random() * (max - min) + min; +const intersects = (circ, rect, right) => { + var c = circ.pos; + var r = circ.r; + if (c.y - r < rect.pos.y + rect.height && c.y + r > rect.pos.y) { + if (right) { + return c.x + r > rect.pos.x - rect.width*2 && c.x < rect.pos.x + rect.width + } else { + return c.x - r < rect.pos.x + rect.width*2 && c.x > rect.pos.x - rect.width + } + } + return false; +} + +///////////////////////////// Ball ////////////////////////////////////////// + +function Ball() { + this.r = 4; + this.prevPos = null; + this.originalSpeed = 4; + this.maxSpeed = 6; + + this.reset(); +} +Ball.prototype.reset = function() { + this.speed = this.originalSpeed; + var x = scores[0] < scores[1] || (scores[0] === 0 && scores[1] === 0) ? -this.speed : this.speed; + var bounceAngle = Math.PI/6; + this.velocity = new Vector(x * Math.cos(bounceAngle), this.speed * -Math.sin(bounceAngle)); + this.pos = new Vector(SCREEN_WIDTH/2, random(0, SCREEN_WIDTH)); + this.ballReturn = 0; +}; +Ball.prototype.restart = function() { + this.reset(); + ai.pos = new Vector(SCREEN_WIDTH - ai.width*2, SCREEN_WIDTH/2 - ai.height/2); + player.pos = new Vector(player.width*2, SCREEN_WIDTH/2 - player.height/2); + this.pos = new Vector(SCREEN_WIDTH/2, SCREEN_WIDTH/2); +}; +Ball.prototype.show = function (invert) { + if (this.prevPos != null) { + g.setColor(invert ? -1 : 0); + g.fillCircle(this.prevPos.x, this.prevPos.y, this.prevPos.r); + } + g.setColor(invert ? 0 : -1); + g.fillCircle(this.pos.x, this.pos.y, this.r); + this.prevPos = { + x: this.pos.x, + y: this.pos.y, + r: this.r + }; +}; +function bounceAngle(playerY, ballY, playerHeight, maxHangle) { + let relativeIntersectY = (playerY + (playerHeight/2)) - ballY; + let normalizedRelativeIntersectionY = relativeIntersectY / (playerHeight/2); + let bounceAngle = normalizedRelativeIntersectionY * maxHangle; + return { x: Math.cos(bounceAngle), y: -Math.sin(bounceAngle) }; +} +Ball.prototype.bouncePlayer = function (directionX, directionY, player) { + this.ballReturn++; + this.speed = constrain(this.speed + 2, this.originalSpeed, this.maxSpeed); + var MAX_BOUNCE_ANGLE = 4 * Math.PI/12; + var angle = bounceAngle(player.pos.y, this.pos.y, player.height, MAX_BOUNCE_ANGLE) + this.velocity.x = this.speed * angle.x * directionX; + this.velocity.y = this.speed * angle.y * directionY; + this.ballReturn % 2 === 0 ? sound.ping() : sound.pong(); +}; +Ball.prototype.bounce = function (directionX, directionY, player) { + if (player) + return this.bouncePlayer(directionX, directionY, player); + + if (directionX) { + this.velocity.x = Math.abs(this.velocity.x) * directionX; + } + if (directionY) { + this.velocity.y = Math.abs(this.velocity.y) * directionY; + } +}; +Ball.prototype.fall = function (playerId) { + scores[playerId]++; + if (scores[playerId] >= MAX_SCORE) { + this.restart(); + state = 3; + if (playerId === 1) { + winnerMessage = startOption === 0 ? "AI Wins!" : "Player 2 Wins!"; + } else { + winnerMessage = startOption === 0 ? "You Win!" : "Player 1 Wins!"; + } + } else { + sound.fall(); + this.reset(); + } +}; +Ball.prototype.wallCollision = function () { + if (this.pos.y < 0) { + this.bounce(0, 1); + } else if (this.pos.y > SCREEN_WIDTH) { + this.bounce(0, -1); + } else if (this.pos.x < 0) { + this.fall(1); + } else if (this.pos.x > SCREEN_WIDTH) { + this.fall(0); + } else { + return false; + } + return true; +}; +Ball.prototype.playerCollision = function (player) { + if (intersects(this, player)) { + if (this.pos.x < SCREEN_WIDTH/2) { + this.bounce(1, 1, player); + this.pos.add(new Vector(this.width, 0)); + aiSpeedRandom = random(-1.6, 1.6); + } else { + this.bounce(-1, 1, player); + this.pos.add(new Vector(-(this.width / 2 + 1), 0)); + } + return true; + } + return false; +}; +Ball.prototype.collisions = function () { + return this.wallCollision() || this.playerCollision(player) || this.playerCollision(ai); +}; +Ball.prototype.updatePosition = function () { + var elapsed = new Date().getTime() - this.lastUpdate; + var x = (elapsed / 50) * this.velocity.x; + var y = (elapsed / 50) * this.velocity.y; + this.pos.add(new Vector(x, y)); +}; +Ball.prototype.update = function () { + this.updatePosition(); + this.lastUpdate = new Date().getTime(); + this.collisions(); +}; + +//////////////////////////// Player ///////////////////////////////////////// + +function Player(right) { + this.width = 4; + this.height = 30; + this.pos = new Vector(right ? SCREEN_WIDTH-this.width : this.width, SCREEN_WIDTH/2 - this.height/2); + this.acc = new Vector(0, 0); + this.speed = 15; + this.maxSpeed = 25; + this.prevPos = null; + this.right = right; +} +Player.prototype.show = function () { + if (this.prevPos != null) { + g.setColor(0); + g.fillRect(this.prevPos.x1, this.prevPos.y1, this.prevPos.x2, this.prevPos.y2); + } + g.setColor(-1); + g.fillRect(this.pos.x, this.pos.y, this.pos.x+this.width, this.pos.y+this.height); + this.prevPos = { + x1: this.pos.x, + y1: this.pos.y, + x2: this.pos.x+this.width, + y2: this.pos.y+this.height + }; +}; +Player.prototype.up = function () { + this.acc.y -= this.speed; +}; +Player.prototype.down = function () { + this.acc.y += this.speed; +}; +Player.prototype.stop = function () { + this.acc.y = 0; +}; +Player.prototype.update = function () { + this.acc.y = constrain(this.acc.y, -this.maxSpeed, this.maxSpeed); + this.pos.add(this.acc); + this.pos.y = constrain(this.pos.y, 0, SCREEN_WIDTH-this.height); +}; + +////////////////////////////// AI /////////////////////////////////////////// + +function AI() { + Player.call(this); + this.pos = new Vector(SCREEN_WIDTH-this.width*2, SCREEN_WIDTH/2 - this.height/2); +} +AI.prototype = Object.create(Player.prototype); +AI.prototype.constructor = Player; +AI.prototype.update = function () { + var y = ball.pos.y - this.height/2; + var randomizedY = ball.ballReturn < 3 ? y : y + (aiSpeedRandom * this.height/2); + var yConstrained = constrain(randomizedY, 0, SCREEN_WIDTH-this.height); + this.pos = new Vector(this.pos.x, yConstrained); +}; + +/////////////////////////////// Scenes //////////////////////////////////////// + +function net() { + var dashSize = 5; + for (let y = dashSize/2; y < SCREEN_WIDTH; y += dashSize*2) { + g.setColor(-1); + let halfScreen = SCREEN_WIDTH/2; + g.fillRect(halfScreen-dashSize/2, y, halfScreen+dashSize/2, y+dashSize); + } +} + +function drawScores() { + let x1 = SCREEN_WIDTH/4-5; + let x2 = SCREEN_WIDTH*3/4-5; + + g.setColor(0); + g.setFont('Vector', 20); + g.drawString(prevScores[0], x1, 7); + g.drawString(prevScores[1], x2, 7); + g.setColor(-1); + g.setFont('Vector', 20); + g.drawString(scores[0], x1, 7); + g.drawString(scores[1], x2, 7); + prevScores = scores.slice(); +} + +function drawGameOver() { + g.setFont("Vector", 20); + g.drawString(winnerMessage, startOption === 0 ? 55 : 75, SCREEN_WIDTH/2 - 10); +} + +function showControls(hide) { + g.setColor(hide ? 0 : -1); + g.setFont("Vector", 8); + var topArrowString = ` + ######## + ## + ## ## + ### ## + ### ## + ### +## +`; + + var arrows = [Graphics.createImage(topArrowString), Graphics.createImage(` + ## + ## +#################### + ## + ## +`), Graphics.createImage(topArrowString.split('\n').reverse().join('\n')) + ]; + + g.drawString('UP', 170, 50); + g.drawImage(arrows[0], 200, 40); + g.drawString('DOWN', 156, 120); + g.drawImage(arrows[1], 200, 120); + g.drawString('START', 152, 190); + g.drawImage(arrows[2], 200, 200); +} + +function drawStartScreen(hide) { + g.setColor(hide ? 0 : -1); + g.setFont("Vector", 10); + g.drawString("1 PLAYER", 95, 80); + g.drawString("2 PLAYERS", 95, 110); + + const ball1 = new Ball(); + ball1.prevPos = null; + ball1.pos = new Vector(87, 86); + ball1.show(hide || !(startOption === 0)); + + const ball2 = new Ball(); + ball2.prevPos = null; + ball2.pos = new Vector(87, 116); + ball2.show(hide || !(startOption === 1)); +} + +function drawStartTimer(count, callback) { + setTimeout(_ => { + player.show(); + ai.show(); + net(); + g.setColor(0); + g.fillRect(117-7, 115-7, 117+14, 115+14); + if (count >= 0) { + g.setFont("Vector", 10); + g.drawString(count+1, 115, 115); + g.setColor(-1); + g.drawString(count === 0 ? 'Go!' : count, 115 - (count === 0 ? 4: 0), 115); + drawStartTimer(count - 1, callback); + } else { + g.setColor(0); + g.fillRect(117-7, 115-7, 117+14, 115+14); + callback(); + } + }, 800); +} + +//////////////////////////////// Main ///////////////////////////////////////// + +function onFrame() { + if (state === 1) { + ball.update(); + player.update(); + ai.update(); + ball.show(); + player.show(); + ai.show(); + net(); + ball.show(); + g.flip() + } else if (state === 3) { + g.clear(); + g.setColor(0); + g.fillRect(0,0,240,240); + state++; + } else if (state === 4) { + drawGameOver(); + } else { + player.show(); + ai.show(); + net(); + } + drawScores(); +} + +function startThatGame() { + player.show(); + ai.show(); + net(); + drawScores(); + drawStartTimer(3, () => setInterval(onFrame, 1000 / FPS)); +} + +var player = new Player(); +var ai; +var ball = new Ball(); +var state = 0; +var prevScores = [0, 0]; +var playerBle = null; +var startOption = 0; + +g.clear(); +g.setColor(0); +g.fillRect(0,0,240,240); +showControls(); +setTimeout(() => { + showControls(true); + drawStartScreen(); +}, 2000); + +////////////////////////////// Controls /////////////////////////////////////// + +setWatch(o => { + if (state === 0) { + if (o.state) { + startOption = startOption === 0 ? startOption : startOption - 1; + drawStartScreen(); + } + } else o.state ? player.up() : player.stop(); +}, BTN1, {repeat: true, edge: 'both'}); +setWatch(o => { + if (state === 0) { + if (o.state) { + startOption = startOption === 1 ? startOption : startOption + 1; + drawStartScreen(); + } + } else o.state ? player.down() : player.stop(); +}, BTN2, {repeat: true, edge: 'both'}); +setWatch(o => { + state++; + clearInterval(); + if (state >= 2) { + g.setColor(0); + g.fillRect(0, 0, 240, 240); + ball.show(true); + scores = [0, 0]; + playerBle = null; + ball = new Ball(); + state = 1; + startThatGame(); + } else { + drawStartScreen(true); + showControls(true); + if (startOption === 1) { + ai = new Player(true); + startThatGame(); + } else { + ai = new AI(); + startThatGame(); + } + } +}, BTN3, {repeat: true}); + +setWatch(o => startOption === 1 && (o.state ? ai.up() : ai.stop()), BTN4, {repeat: true, edge: 'both'}); +setWatch(o => startOption === 1 && (o.state ? ai.down() : ai.stop()), BTN5, {repeat: true, edge: 'both'}); diff --git a/apps/pong/pong.png b/apps/pong/pong.png new file mode 100644 index 000000000..cc97f58f7 Binary files /dev/null and b/apps/pong/pong.png differ diff --git a/apps/pparrot/ChangeLog b/apps/pparrot/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/pparrot/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/qrcode/ChangeLog b/apps/qrcode/ChangeLog new file mode 100644 index 000000000..e2ae6b02a --- /dev/null +++ b/apps/qrcode/ChangeLog @@ -0,0 +1,2 @@ +0.01: New App! +0.02: Add posibillity to generate Wifi code. diff --git a/apps/qrcode/app-icon.js b/apps/qrcode/app-icon.js new file mode 100644 index 000000000..5905fa7e9 --- /dev/null +++ b/apps/qrcode/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgP/AEX8gE8nkAn4FSngCWF6xfYDgIABHAQFPDQXD4YgDApxNDMooFOAQIdDAqIvWfcYA=")) diff --git a/apps/qrcode/qrcode.png b/apps/qrcode/app.png similarity index 100% rename from apps/qrcode/qrcode.png rename to apps/qrcode/app.png diff --git a/apps/qrcode/custom.html b/apps/qrcode/custom.html new file mode 100644 index 000000000..9bcb79163 --- /dev/null +++ b/apps/qrcode/custom.html @@ -0,0 +1,115 @@ +<html> + <head> + <link rel="stylesheet" href="../../css/spectre.min.css"> + </head> + <body> + <input type="radio" id="useURL" name="mode" checked/> + <label for="useURL">Use URL:</label> + <input type="text" id="url" class="form-input" value="http://espruino.com"> + <hr> + <input type="radio" id="useWIFI" name="mode"/> + <label for="useWIFI">Use Wifi Credentials:</label> + <input type="text" id="ssid" class="form-input" value=""> + <p>Wifi password: <input type="password" id="password" class="form-input" value=""></p> + <div class="form-group"> + <label for="encryption" class="control-label">Encryption</label> + <div class="input-group"> + <select name="encryption" id="encryption" class="form-control"> + <option value="WPA">WPA/WPA2</option> + <option value="WEP">WEP</option> + <option value="nopass">None</option> + </select> + </div> + </div> + <div> + <input type="checkbox" id="hidden" name="hidden"/> + <label for="hidden">Wifi is hidden</label> + </div> + <p>Try your QR Code: <div id="qrcode"></div></p> + <p>Click <button id="upload" class="btn btn-primary">Upload</button></p> + + <script src="../../core/lib/customize.js"></script> + <script src="../../core/lib/qrcode.min.js"></script><!-- https://davidshimjs.github.io/qrcodejs/ --> + <script src="../../core/lib/heatshrink.js"></script> + <script src="../../core/lib/imageconverter.js"></script> + + <script> + //https://github.com/evgeni/qifi/blob/gh-pages/index.html#L168 + function escapeString (string) { + var to_escape = ['\\', ';', ',', ':', '"']; + var hex_only = /^[0-9a-f]+$/i; + var output = ""; + for (var i=0; i<string.length; i++) { + if(string[i].includes(to_escape)) { + output += '\\'+string[i]; + } + else { + output += string[i]; + } + } + return output; + } + function generateWifiString(ssid, password, hidden,encryption){ + //https://github.com/evgeni/qifi/blob/gh-pages/index.html#L198 + var qrstring = 'WIFI:S:'+escapeString(ssid)+';T:'+encryption+';P:'+escapeString(password)+';'; + if (hidden) { + qrstring += 'H:true'; + } + return qrstring; + } + function refreshQRCode(){ + qrcode.clear(); // clear the code. + if(document.getElementById("useWIFI").checked){ + const ssid = document.getElementById("ssid").value; + const password = document.getElementById("password").value; + const encryption = document.getElementById("encryption").value; + const hidden = document.getElementById("hidden").checked; + const wifiString = generateWifiString(ssid, password, hidden, encryption); + qrcode.makeCode(wifiString); + }else{ + qrcode.makeCode(document.getElementById("url").value); + } + } + var qrcode = new QRCode("qrcode", { + text: document.getElementById("url").value, + width: 200, + height: 200, + colorDark : "#000000", + colorLight : "#ffffff", + }); + + document.getElementById("url").addEventListener("change", refreshQRCode); + document.getElementById("ssid").addEventListener("change",refreshQRCode); + document.getElementById("password").addEventListener("change",refreshQRCode); + document.getElementById("encryption").addEventListener("change",refreshQRCode); + document.getElementById("hidden").addEventListener("change",refreshQRCode); + document.getElementById("useURL").addEventListener("change",refreshQRCode); + document.getElementById("useWIFI").addEventListener("change",refreshQRCode); + document.getElementById("upload").addEventListener("click", function() { + var content = document.getElementById("url").value; + if(document.getElementById("useWIFI").checked){ + content = document.getElementById("ssid").value + } + var img = imageconverter.canvastoString(document.getElementsByTagName("canvas")[0],{mode:"1bit",output:"string",compression:true}); + var app = `var img = ${img}; +var content = ${JSON.stringify(content)}; +g.setColor(1,1,1); +g.fillRect(0,0,239,239); +g.drawImage(img,20,20); +g.setFontAlign(0,0); +g.setFont("6x8"); +g.setColor(0,0,0); +g.drawString(content,120,230); +g.setColor(1,1,1); +`; + sendCustomizedApp({ + storage:[ + {name:"qrcode.app.js", url:"app.js", content:app}, + ] + }); + + }); + + </script> + </body> +</html> diff --git a/apps/qrcode/qrcode.html b/apps/qrcode/qrcode.html deleted file mode 100644 index 5d372aa59..000000000 --- a/apps/qrcode/qrcode.html +++ /dev/null @@ -1,56 +0,0 @@ -<html> - <head> - <link rel="stylesheet" href="../../css/spectre.min.css"> - </head> - <body> - - <p>Enter a URL: <input type="text" id="url" class="form-input" value="http://espruino.com"></p> - <p>Try your QR Code: <div id="qrcode"></div></p> - <p>Click <button id="upload" class="btn btn-primary">Upload</button></p> - - <script src="../../lib/customize.js"></script> - <script src="../../lib/qrcode.min.js"></script><!-- https://davidshimjs.github.io/qrcodejs/ --> - <script src="https://espruino.github.io/EspruinoWebTools/heatshrink.js"></script> - <script src="https://espruino.github.io/EspruinoWebTools/imageconverter.js"></script> - - <script> - - var qrcode = new QRCode("qrcode", { - text: document.getElementById("url").value, - width: 200, - height: 200, - colorDark : "#000000", - colorLight : "#ffffff", - }); - - document.getElementById("url").addEventListener("change", function() { - qrcode.clear(); // clear the code. - qrcode.makeCode(document.getElementById("url").value); // make another code. - }); - document.getElementById("upload").addEventListener("click", function() { - var url = document.getElementById("url").value; - var img = imageconverter.canvastoString(document.getElementsByTagName("canvas")[0],{mode:"1bit",output:"string",compression:true}); - var app = `var img = ${img}; -var url = ${JSON.stringify(url)}; -g.setColor(1,1,1); -g.fillRect(0,0,239,239); -g.drawImage(img,20,20); -g.setFontAlign(0,0); -g.setFont("6x8"); -g.setColor(0,0,0); -g.drawString(url,120,230); -g.setColor(1,1,1); -`; - var icon = `require("heatshrink").decompress(atob("mEwgP/AEX8gE8nkAn4FSngCWF6xfYDgIABHAQFPDQXD4YgDApxNDMooFOAQIdDAqIvWfcYA="))`; - sendCustomizedApp({ - storage:[ - {name:"qrcode.app.js", content:app}, - {name:"qrcode.img", content:icon, evaluate:true}, - ] - }); - - }); - - </script> - </body> -</html> diff --git a/apps/rclock/ChangeLog b/apps/rclock/ChangeLog new file mode 100644 index 000000000..fa62e12fb --- /dev/null +++ b/apps/rclock/ChangeLog @@ -0,0 +1,3 @@ +0.01: First published version of app +0.02: Added support for locale and 12H clock +0.03: Added HR indication to clock diff --git a/apps/rclock/app-icon.js b/apps/rclock/app-icon.js new file mode 100644 index 000000000..62f5310d5 --- /dev/null +++ b/apps/rclock/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+If4A/AH4AXqwBEF9VWlYxEAoIAllYuGGwIxnSxAwkR4InCFIbGmF4TCCGAYEBSgK/kXYQxFetDzCLYhgjeBQ3EGE69ESwgwoZYiSpMAgCEGFRfqYQrDblRfRMDdU0QFDp2iAAN4HIowBLYYwXvHG4w0D4wtB0QDBGApcCGYqLSEgIvEAwIqCHQNUYArdaKwIlBRwYpDGgIvEL4QxBYDIvEAAhpBpxZaF6BeBvAIFL4qVXF44uIF4pffFxI0GF7ouKlbrClaNXF4wEB0VUAAUqF4qTEF7heBAAhjDLQS+CL7MqqgECLgZfNGDIAORIaNZACCOBLIbvaFxy/ERtDpCAgYCDF1DsnFgS2ERk4sBF4hhBMYgAiE4bsDF0zAKMFABBXkxZEX4QunWwS4CFtCMEFsN4AAOiAYcAqgGB0UqgGip2iqgvcD4IuCAYgwBAoINBAIN4F7gkBAAplCGgVUNQhfcqlOAAIDCgEqAQIBBAoKXBAQIAL")) \ No newline at end of file diff --git a/apps/rclock/app.png b/apps/rclock/app.png new file mode 100644 index 000000000..7950d4bc3 Binary files /dev/null and b/apps/rclock/app.png differ diff --git a/apps/rclock/rclock.app.js b/apps/rclock/rclock.app.js new file mode 100644 index 000000000..f9b8a9e6f --- /dev/null +++ b/apps/rclock/rclock.app.js @@ -0,0 +1,233 @@ +{ + var minutes; + var seconds; + var hours; + var date; + var first = true; + var locale = require('locale'); + var _12hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"] || false; + + //HR variables + var id = 0; + var grow = true; + var size=10; + + //Screen dimensions + const screen = { + width: g.getWidth(), + height: g.getWidth(), + middle: g.getWidth() / 2, + center: g.getHeight() / 2, + }; + + // Ssettings + const settings = { + time: { + color: '#f0af00', + shadow: '#CF7500', + font: 'Vector', + size: 60, + middle: screen.middle - 30, + center: screen.center, + }, + date: { + color: '#f0af00', + shadow: '#CF7500', + font: 'Vector', + size: 15, + middle: screen.height - 20, // at bottom of screen + center: screen.center, + }, + circle: { + colormin: '#eeeeee', + colorsec: '#bbbbbb', + width: 10, + middle: screen.middle, + center: screen.center, + height: screen.height + }, + hr: { + color: '#333333', + size: 10, + x: screen.center, + y: screen.middle + 45 + } + }; + + const dateStr = function (date) { + return locale.date(new Date(), 1); + }; + + const getArcXY = function (centerX, centerY, radius, angle) { + var s, r = []; + s = 2 * Math.PI * angle / 360; + r.push(centerX + Math.round(Math.cos(s) * radius)); + r.push(centerY + Math.round(Math.sin(s) * radius)); + + return r; + }; + + const drawMinArc = function (sections, color) { + g.setColor(color); + rad = (settings.circle.height / 2) - 20; + r1 = getArcXY(settings.circle.middle, settings.circle.center, rad, sections * (360 / 60) - 90); + //g.setPixel(r[0],r[1]); + r2 = getArcXY(settings.circle.middle, settings.circle.center, rad - settings.circle.width, sections * (360 / 60) - 90); + //g.setPixel(r[0],r[1]); + g.drawLine(r1[0], r1[1], r2[0], r2[1]); + g.setColor('#333333'); + g.drawCircle(settings.circle.middle, settings.circle.center, rad - settings.circle.width - 4) + }; + + const drawSecArc = function (sections, color) { + g.setColor(color); + rad = (settings.circle.height / 2) - 40; + r1 = getArcXY(settings.circle.middle, settings.circle.center, rad, sections * (360 / 60) - 90); + //g.setPixel(r[0],r[1]); + r2 = getArcXY(settings.circle.middle, settings.circle.center, rad - settings.circle.width, sections * (360 / 60) - 90); + //g.setPixel(r[0],r[1]); + g.drawLine(r1[0], r1[1], r2[0], r2[1]); + g.setColor('#333333'); + g.drawCircle(settings.circle.middle, settings.circle.center, rad - settings.circle.width - 4) + }; + + const drawClock = function () { + + currentTime = new Date(); + + //Set to initial time when started + if (first == true) { + minutes = currentTime.getMinutes(); + seconds = currentTime.getSeconds(); + for (count = 0; count <= minutes; count++) { + drawMinArc(count, settings.circle.colormin); + } + + for (count = 0; count <= seconds; count++) { + drawSecArc(count, settings.circle.colorsec); + } + first = false; + } + + // Reset seconds + if (seconds == 59) { + g.setColor('#000000'); + g.fillCircle(settings.circle.middle, settings.circle.center, (settings.circle.height / 2) - 40); + } + // Reset minutes + if (minutes == 59 && seconds == 59) { + g.setColor('#000000'); + g.fillCircle(settings.circle.middle, settings.circle.center, (settings.circle.height / 2) - 20); + } + + //Get date as a string + date = dateStr(currentTime); + + // Update minutes when needed + if (minutes != currentTime.getMinutes()) { + minutes = currentTime.getMinutes(); + drawMinArc(minutes, settings.circle.colormin); + } + + //Update seconds when needed + if (seconds != currentTime.getSeconds()) { + seconds = currentTime.getSeconds(); + drawSecArc(seconds, settings.circle.colorsec); + } + + //Write the time as configured in the settings + hours = currentTime.getHours(); + if (_12hour && hours > 13) { + hours = hours - 12; + } + + var meridian; + + if (typeof locale.meridian === "function") { + meridian = locale.meridian(new Date()); + } else { + meridian = ""; + } + + var timestr; + + if (meridian.length > 0 && _12hour) { + timestr = hours + " " + meridian; + } else { + timestr = hours; + } + g.setFontAlign(0, 0, 0); + g.setColor(settings.time.color); + g.setFont(settings.time.font, settings.time.size); + g.drawString(timestr, settings.time.center, settings.time.middle); + + //Write the date as configured in the settings + g.setColor(settings.date.color); + g.setFont(settings.date.font, settings.date.size); + g.drawString(date, settings.date.center, settings.date.middle); + }; + + //setInterval for HR visualisation + const newBeats = function (hr) { + if (id != 0) { + changeInterval(id, 6e3 / hr.bpm); + } else { + id = setInterval(drawHR, 6e3 / hr.bpm); + } + }; + + //visualize HR with circles pulsating + const drawHR = function () { + if (grow && size < settings.hr.size) { + size++; + } + + if (!grow && size > 3) { + size--; + } + + if (size == settings.hr.size || size == 3) { + grow = !grow; + } + + if (grow) { + color = settings.hr.color; + g.setColor(color); + g.fillCircle(settings.hr.x, settings.hr.y, size); + } else { + color = "#000000"; + g.setColor(color); + g.drawCircle(settings.hr.x, settings.hr.y, size); + } + }; + + // clean app screen + g.clear(); + Bangle.loadWidgets(); + Bangle.drawWidgets(); + + //manage when things should be enabled and not + Bangle.on('lcdPower', function (on) { + if (on) { + Bangle.setHRMPower(1); + } else { + Bangle.setHRMPower(0); + } + }); + + // refesh every second + setInterval(drawClock, 1E3); + + //start HR monitor and update frequency of update + Bangle.setHRMPower(1); + Bangle.on('HRM', function (d) { + newBeats(d); + }); + + // draw now + drawClock(); + + // Show launcher when middle button pressed + setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); + +} \ No newline at end of file diff --git a/apps/rndmclk/ChangeLog b/apps/rndmclk/ChangeLog new file mode 100644 index 000000000..1f53ea4ae --- /dev/null +++ b/apps/rndmclk/ChangeLog @@ -0,0 +1,3 @@ +0.01: New widget +0.02: Less invasive, change default clock setting instead of directly loading the new clock (no longer breaks Gadgetbridge notifications) +0.03: Only changes when the widget id reloaded (no longer uses LCD turning off) diff --git a/apps/rndmclk/README.md b/apps/rndmclk/README.md new file mode 100644 index 000000000..d75a53343 --- /dev/null +++ b/apps/rndmclk/README.md @@ -0,0 +1,6 @@ +# Summary +Random Clock is a widget that will randomly show one of the installed watch faces each time after the widget is (re-)loaded. + +# How it works +Everytime the widget is reloaded, it randomly changes the clock. When you long press BTN 3 the next time, +you might (or might not, it's random after all) see another watch face. \ No newline at end of file diff --git a/apps/rndmclk/rndmclk.png b/apps/rndmclk/rndmclk.png new file mode 100644 index 000000000..9519b8d09 Binary files /dev/null and b/apps/rndmclk/rndmclk.png differ diff --git a/apps/rndmclk/widget.js b/apps/rndmclk/widget.js new file mode 100644 index 000000000..479d8b2c3 --- /dev/null +++ b/apps/rndmclk/widget.js @@ -0,0 +1,33 @@ +(() => { + let currentClock = ""; + + /** + * Random value between zero (inclusive) and max (exclusive) + * @param {int} max + */ + function getRandomInt(max) { + return Math.floor(Math.random() * Math.floor(max)); + } + + function loadRandomClock() { + // Find available clock apps (same way as in the bootloader) + var clockApps = require("Storage").list(/\.info$/).map(app => require("Storage").readJSON(app, 1) || {}).filter(app => app.type == "clock").sort((a, b) => a.sortorder - b.sortorder); + + if (clockApps && clockApps.length > 0) { + var clockIndex = getRandomInt(clockApps.length); + + // Only update the file if the clock really changed to be nice to the FLASH mem + if (clockApps[clockIndex].src != currentClock) { + currentClock = clockApps[clockIndex].src; + settings = require("Storage").readJSON('setting.json', 1); + settings.clock = clockApps[clockIndex].src; + require("Storage").write('setting.json', settings); + + console.log("RandomClockWidget set the clock to '" + clockApps[clockIndex].name + "'"); + } + } + } + + loadRandomClock(); + +})(); \ No newline at end of file diff --git a/apps/route/ChangeLog b/apps/route/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/route/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/route/app-icon.js b/apps/route/app-icon.js new file mode 100644 index 000000000..8410cad40 --- /dev/null +++ b/apps/route/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgIkhvgFE/wEDgOHAocDgYFEgOAAp4XEEYsB4w1E5hBKnByFKw8/AQNAAQP/4EAAIMB4HggBABHoNwCwUGE4kOgEYBAMAhk+hgIBAoM/hkEAoMIv8MC4QFChARCAoIMCDoQXChkcjA1EAoJBBg5dCJoJHDKYWAsCGD4AJBAAXBDYIlCsYFBGwUzPok+AokcsOOmIUCAogAWA==")) diff --git a/apps/route/route.png b/apps/route/app.png similarity index 100% rename from apps/route/route.png rename to apps/route/app.png diff --git a/apps/route/route.html b/apps/route/custom.html similarity index 94% rename from apps/route/route.html rename to apps/route/custom.html index 2417aa232..124c92a31 100644 --- a/apps/route/route.html +++ b/apps/route/custom.html @@ -25,7 +25,7 @@ <input class="form-input" type="file" id="fileLoader"/></p> <p><button id="upload" style="display:none" class="btn btn-primary">Upload</button></p> <pre id="log"></pre> -<script src="../../lib/customize.js"></script> +<script src="../../core/lib/customize.js"></script> <script> var xmlText = ""; var xmlDoc; @@ -240,12 +240,10 @@ Bangle.setGPSPower(1); Bangle.setCompassPower(1); g.clear(); `; -var icon = `require("heatshrink").decompress(atob("mEwgIkhvgFE/wEDgOHAocDgYFEgOAAp4XEEYsB4w1E5hBKnByFKw8/AQNAAQP/4EAAIMB4HggBABHoNwCwUGE4kOgEYBAMAhk+hgIBAoM/hkEAoMIv8MC4QFChARCAoIMCDoQXChkcjA1EAoJBBg5dCJoJHDKYWAsCGD4AJBAAXBDYIlCsYFBGwUzPok+AokcsOOmIUCAogAWA=="))`; sendCustomizedApp({ storage:[ - {name:"route.app.js", content:app}, - {name:"route.img", content:icon, evaluate:true}, + {name:"route.app.js", url:"app.js", content:app} ] }); }); diff --git a/apps/scolor/ChangeLog b/apps/scolor/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/scolor/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/scolor/show-color.js b/apps/scolor/show-color.js index 9a28b26dc..e248ee80d 100644 --- a/apps/scolor/show-color.js +++ b/apps/scolor/show-color.js @@ -1,60 +1,60 @@ /* jshint esversion: 6 */ (function() { - const colors = { - 0: { value: 0x0000, name: "Black" }, - 1: { value: 0x000F, name: "Navy" }, - 2: { value: 0x03E0, name: "DarkGreen" }, - 3: { value: 0x03EF, name: "DarkCyan" }, - 4: { value: 0x7800, name: "Maroon" }, - 5: { value: 0x780F, name: "Purple" }, - 6: { value: 0x7BE0, name: "Olive" }, - 7: { value: 0xC618, name: "LightGray" }, - 8: { value: 0x7BEF, name: "DarkGrey" }, - 9: { value: 0x001F, name: "Blue" }, - 10: { value: 0x07E0, name: "Green" }, - 11: { value: 0x07FF, name: "Cyan" }, - 12: { value: 0xF800, name: "Red" }, - 13: { value: 0xF81F, name: "Magenta" }, - 14: { value: 0xFFE0, name: "Yellow" }, - 15: { value: 0xFFFF, name: "White" }, - 16: { value: 0xFD20, name: "Orange" }, - 17: { value: 0xAFE5, name: "GreenYellow" }, - 18: { value: 0xF81F, name: "Pink" }, - }; + const colors = { + 0: { value: 0x0000, name: "Black" }, + 1: { value: 0x000F, name: "Navy" }, + 2: { value: 0x03E0, name: "DarkGreen" }, + 3: { value: 0x03EF, name: "DarkCyan" }, + 4: { value: 0x7800, name: "Maroon" }, + 5: { value: 0x780F, name: "Purple" }, + 6: { value: 0x7BE0, name: "Olive" }, + 7: { value: 0xC618, name: "LightGray" }, + 8: { value: 0x7BEF, name: "DarkGrey" }, + 9: { value: 0x001F, name: "Blue" }, + 10: { value: 0x07E0, name: "Green" }, + 11: { value: 0x07FF, name: "Cyan" }, + 12: { value: 0xF800, name: "Red" }, + 13: { value: 0xF81F, name: "Magenta" }, + 14: { value: 0xFFE0, name: "Yellow" }, + 15: { value: 0xFFFF, name: "White" }, + 16: { value: 0xFD20, name: "Orange" }, + 17: { value: 0xAFE5, name: "GreenYellow" }, + 18: { value: 0xF81F, name: "Pink" }, + }; - const maxColors = 19; - var index = 0; + const maxColors = 19; + var index = 0; - function drawColor() { + function drawColor() { - // draw filled rectangle - g.setColor(colors[index % maxColors].value); - g.fillRect(0, 24, g.getWidth(), g.getHeight()); + // draw filled rectangle + g.setColor(colors[index % maxColors].value); + g.fillRect(0, 24, g.getWidth(), g.getHeight()); - // draw value name of color - g.setFontAlign(0, 0); - g.setColor(0xFFFF); - if (colors[index % maxColors].name == "White") - g.setColor(0); - g.setFont("6x8", 4); - g.drawString('0x' + colors[index % maxColors].value.toString(16), 120, 80); - g.setFont("6x8", 3); - g.drawString(colors[index % maxColors].name, 120, 160); + // draw value name of color + g.setFontAlign(0, 0); + g.setColor(0xFFFF); + if (colors[index % maxColors].name == "White") + g.setColor(0); + g.setFont("6x8", 4); + g.drawString('0x' + colors[index % maxColors].value.toString(16), 120, 80); + g.setFont("6x8", 3); + g.drawString(colors[index % maxColors].name, 120, 160); - // draw next button info - g.setFont("6x8", 2); - g.setFontAlign(0, 0, 3); - g.drawString("Next", 230, 60); + // draw next button info + g.setFont("6x8", 2); + g.setFontAlign(0, 0, 3); + g.drawString("Next", 230, 60); - // set watches for button 1 - index++; - setWatch(drawColor, BTN1, { repeate: true }); + // set watches for button 1 + index++; + setWatch(drawColor, BTN1, { repeate: true }); - } + } - g.clear(); - setWatch(drawColor, BTN1, { repeate: false }); - E.showMessage("Press BTN1\nto start"); + g.clear(); + setWatch(drawColor, BTN1, { repeate: false }); + E.showMessage("Press BTN1\nto start"); })(); diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index 3acfb5fb0..6a5b1dd76 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -18,3 +18,9 @@ 0.14: Reduce memory usage when running app settings page 0.15: Reduce memory usage when running default clock chooser (#294) 0.16: Reduce memory usage further when running app settings page +0.17: Remove need for "settings" in appid.info +0.18: Don't overwrite existing settings on app update +0.19: Allow BLE HID settings, add README.md +0.20: Fix set time menu, allow dates to roll over +0.21: Add passkey pairing option (BETA) + Add whitelist option (fix #78) diff --git a/apps/setting/README.md b/apps/setting/README.md new file mode 100644 index 000000000..d7607539a --- /dev/null +++ b/apps/setting/README.md @@ -0,0 +1,33 @@ +# Settings + +This is Bangle.js's settings menu + +* **Make Connectable** regardless of the current Bluetooth settings, makes Bangle.js so you can connect to it (while the window is up) +* **App/Widget Settings** settings specific to installed applications +* **BLE** Bluetooth Settings menu - see below. +* **Debug Info** should debug info be shown on the watch's screen or not? +* **Beep** most Bangle.js do not have a speaker inside, but they can use the vibration motor to beep in different pitches. You can change the behaviour here to use a Piezo speaker if one is connected +* **Vibration** enable/disable the vibration motor +* **Locale** set time zone/whether the clock is 12/24 hour (for supported clocks) +* **Select Clock** if you have more than one clock face, select the default one +* **HID** When Bluetooth is enabled, Bangle.js can appear as a Bluetooth Keyboard/Joystick/etc to send keypresses to a connected device. + * **NOTE:** on some platforms enabling HID can cause you problems when trying to connect to Bangle.js to upload apps. +* **Set Time** Configure the current time - Note that this can be done much more easily by choosing 'Set Time' from the App Loader +* **LCD** Configure settings about the screen. How long it stays on, how bright it is, and when it turns on - see below. +* **Reset Settings** Reset the settings to defaults +* **Turn Off** Turn Bangle.js off + +## BLE - Bluetooth Settings + +* **BLE** is Bluetooth LE enabled and the watch connectable? +* **Programmable** if BLE is on, can the watch be connected to in order to program/upload apps? As long as your watch firmware is up to date, Gadgetbridge will work even with `Programmable` set to `Off`. +* **Passkey BETA** allows you to set a passkey that is required to connect and pair to Bangle.js. **Note:** This is Beta and you will almost certainly encounter issues connecting with Web Bluetooth using this option. +* **Whitelist** allows you to specify only specific devices that you will let connect to your Bangle.js. Simply choose the menu item, then `Add Device`, and then connect to Bangle.js with the device you want to add. If you are already connected you will have to disconnect first. Changes will take effect when you exit the `Settings` app. + * **NOTE:** iOS devices and newer Android devices often implement Address Randomisation and change their Bluetooth address every so often. If you device's address changes, you will be unable to connect until you update the whitelist again. + +## LCD + +* **LCD Brightness** set how bright the LCD is. Due to hardware limitations in the LCD backlight, you may notice flicker if the LCD is not at 100% brightness. +* **LCD Timeout** how long should the LCD stay on for if no activity is detected. 0=stay on forever +* **Wake on X** should the given activity wake up the Bangle.js LCD? +* **Twist X** these options adjust the sensitivity of `Wake on Twist` to ensure Bangle.js wakes up with just the right amount of wrist movement. diff --git a/apps/setting/boot.js b/apps/setting/boot.js index b437cf744..5b556a25f 100644 --- a/apps/setting/boot.js +++ b/apps/setting/boot.js @@ -3,4 +3,7 @@ if (!settings) return; if (settings.options) Bangle.setOptions(settings.options); if (settings.brightness && settings.brightness!=1) Bangle.setLCDBrightness(settings.brightness); + if (settings.passkey!==undefined && settings.passkey.length==6) NRF.setSecurity({passkey:settings.passkey, mitm:1, display:1}); + if (settings.whitelist) NRF.on('connect', function(addr) { if (!settings.whitelist.includes(addr)) NRF.disconnect(); }); + delete settings; })() diff --git a/apps/setting/settings-default.json b/apps/setting/settings-default.json deleted file mode 100644 index c61fd6109..000000000 --- a/apps/setting/settings-default.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - ble: true, // Bluetooth enabled by default - blerepl: true, // Is REPL on Bluetooth - can Espruino IDE be used? - log: false, // Do log messages appear on screen? - timeout: 10, // Default LCD timeout in seconds - vibrate: true, // Vibration enabled by default. App must support - beep: "vib", // Beep enabled by default. App must support - timezone: 0, // Set the timezone for the device - HID : false, // BLE HID mode, off by default - clock: null, // a string for the default clock's name - "12hour" : false, // 12 or 24 hour clock? - // welcomed : undefined/true (whether welcome app should show) - brightness: 1, // LCD brightness from 0 to 1 - options: { - wakeOnBTN1: true, - wakeOnBTN2: true, - wakeOnBTN3: true, - wakeOnFaceUp: false, - wakeOnTouch: false, - wakeOnTwist: true, - twistThreshold: 819.2, - twistMaxY: -800, - twistTimeout: 1000 - } -} diff --git a/apps/setting/settings.js b/apps/setting/settings.js index d0d88ce20..8fa919535 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -61,26 +61,13 @@ const boolFormat = v => v ? "On" : "Off"; function showMainMenu() { var beepV = [false, true, "vib"]; var beepN = ["Off", "Piezo", "Vibrate"]; + var hidV = [false, "kbmedia", "kb", "joy"]; + var hidN = ["Off", "Kbrd & Media", "Kbrd","Joystick"]; const mainmenu = { '': { 'title': 'Settings' }, 'Make Connectable': ()=>makeConnectable(), 'App/Widget Settings': ()=>showAppSettingsMenu(), - 'BLE': { - value: settings.ble, - format: boolFormat, - onchange: () => { - settings.ble = !settings.ble; - updateSettings(); - } - }, - 'Programmable': { - value: settings.blerepl, - format: boolFormat, - onchange: () => { - settings.blerepl = !settings.blerepl; - updateSettings(); - } - }, + 'BLE': ()=>showBLEMenu(), 'Debug Info': { value: settings.log, format: v => v ? "Show" : "Hide", @@ -115,10 +102,11 @@ function showMainMenu() { 'Locale': ()=>showLocaleMenu(), 'Select Clock': ()=>showClockMenu(), 'HID': { - value: settings.HID, - format: boolFormat, - onchange: () => { - settings.HID = !settings.HID; + value: 0 | hidV.indexOf(settings.HID), + min: 0, max: 3, + format: v => hidN[v], + onchange: v => { + settings.HID = hidV[v]; updateSettings(); } }, @@ -131,6 +119,99 @@ function showMainMenu() { return E.showMenu(mainmenu); } +function showBLEMenu() { + E.showMenu({ + 'BLE': { + value: settings.ble, + format: boolFormat, + onchange: () => { + settings.ble = !settings.ble; + updateSettings(); + } + }, + 'Programmable': { + value: settings.blerepl, + format: boolFormat, + onchange: () => { + settings.blerepl = !settings.blerepl; + updateSettings(); + } + }, + 'Passkey BETA': { + value: settings.passkey?settings.passkey:"none", + onchange: () => setTimeout(showPasskeyMenu) // graphical_menu redraws after the call + }, + 'Whitelist': { + value: settings.whitelist?(settings.whitelist.length+" devs"):"off", + onchange: () => setTimeout(showWhitelistMenu) // graphical_menu redraws after the call + }, + '< Back': ()=>showMainMenu() + }); +} + +function showPasskeyMenu() { + var menu = { + "Disable" : () => { + settings.passkey = undefined; + updateSettings(); + showBLEMenu(); + } + }; + if (!settings.passkey || settings.passkey.length!=6) + settings.passkey = "123456"; + for (var i=0;i<6;i++) (function(i){ + menu[`Digit ${i+1}`] = { + value : 0|settings.passkey[i], + min: 0, max: 9, + onchange: v => { + var p = settings.passkey.split(""); + p[i] = v; + settings.passkey = p.join(""); + updateSettings(); + } + }; + })(i); + menu['< Back']=()=>showBLEMenu(); + E.showMenu(menu); +} + +function showWhitelistMenu() { + var menu = { + "Disable" : () => { + settings.whitelist = undefined; + updateSettings(); + showBLEMenu(); + } + }; + if (settings.whitelist) settings.whitelist.forEach(function(d){ + menu[d.substr(0,17)] = function() { + E.showPrompt('Remove\n'+d).then((v) => { + if (v) { + settings.whitelist.splice(settings.whitelist.indexOf(d),1); + updateSettings(); + } + setTimeout(showWhitelistMenu, 50); + }); + } + }); + menu['Add Device']=function() { + E.showAlert("Connect device\nto add to\nwhitelist","Whitelist").then(function() { + NRF.removeAllListeners('connect'); + showWhitelistMenu(); + }); + NRF.removeAllListeners('connect'); + NRF.on('connect', function(addr) { + if (!settings.whitelist) settings.whitelist=[]; + settings.whitelist.push(addr); + updateSettings(); + NRF.removeAllListeners('connect'); + showWhitelistMenu(); + }); + }; + menu['< Back']=()=>showBLEMenu(); + E.showMenu(menu); +} + function showLCDMenu() { const lcdMenu = { '': { 'title': 'LCD' }, @@ -328,83 +409,52 @@ function showClockMenu() { function showSetTimeMenu() { d = new Date(); const timemenu = { - '': { - 'title': 'Set Time', - 'predraw': function () { - d = new Date(); - timemenu.Hour.value = d.getHours(); - timemenu.Minute.value = d.getMinutes(); - timemenu.Second.value = d.getSeconds(); - timemenu.Date.value = d.getDate(); - timemenu.Month.value = d.getMonth() + 1; - timemenu.Year.value = d.getFullYear(); - } + '': { 'title': 'Set Time' }, + '< Back': function () { + setTime(d.getTime() / 1000); + showMainMenu(); }, - '< Back': ()=>showMainMenu(), 'Hour': { value: d.getHours(), - min: 0, - max: 23, - step: 1, - onchange: v => { - d = new Date(); - d.setHours(v); - setTime(d.getTime() / 1000); + onchange: function (v) { + this.value = (v+24)%24; + d.setHours(this.value); } }, 'Minute': { value: d.getMinutes(), - min: 0, - max: 59, - step: 1, - onchange: v => { - d = new Date(); - d.setMinutes(v); - setTime(d.getTime() / 1000); + onchange: function (v) { + this.value = (v+60)%60; + d.setMinutes(this.value); } }, 'Second': { value: d.getSeconds(), - min: 0, - max: 59, - step: 1, - onchange: v => { - d = new Date(); - d.setSeconds(v); - setTime(d.getTime() / 1000); + onchange: function (v) { + this.value = (v+60)%60; + d.setSeconds(this.value); } }, 'Date': { value: d.getDate(), - min: 1, - max: 31, - step: 1, - onchange: v => { - d = new Date(); - d.setDate(v); - setTime(d.getTime() / 1000); + onchange: function (v) { + this.value = ((v+30)%31)+1; + d.setDate(this.value); } }, 'Month': { value: d.getMonth() + 1, - min: 1, - max: 12, - step: 1, - onchange: v => { - d = new Date(); - d.setMonth(v - 1); - setTime(d.getTime() / 1000); + onchange: function (v) { + this.value = ((v+11)%12)+1; + d.setMonth(this.value - 1); } }, 'Year': { value: d.getFullYear(), min: 2019, max: 2100, - step: 1, - onchange: v => { - d = new Date(); + onchange: function (v) { d.setFullYear(v); - setTime(d.getTime() / 1000); } } }; @@ -416,10 +466,19 @@ function showAppSettingsMenu() { '': { 'title': 'App Settings' }, '< Back': ()=>showMainMenu(), } - const apps = storage.list(/\.info$/) - .map(app => {var a=storage.readJSON(app, 1);return (a&&a.settings)?{sortorder:a.sortorder,name:a.name,settings:a.settings}:undefined}) - .filter(app => app) // filter out any undefined apps - .sort((a, b) => a.sortorder - b.sortorder) + const apps = storage.list(/\.settings\.js$/) + .map(s => s.substr(0, s.length-12)) + .map(id => { + const a=storage.readJSON(id+'.info',1) || {name: id}; + return {id:id,name:a.name,sortorder:a.sortorder}; + }) + .sort((a, b) => { + const n = (0|a.sortorder)-(0|b.sortorder); + if (n) return n; // do sortorder first + if (a.name<b.name) return -1; + if (a.name>b.name) return 1; + return 0; + }) if (apps.length === 0) { appmenu['No app has settings'] = () => { }; } @@ -433,10 +492,7 @@ function showAppSettings(app) { E.showMessage(`${app.name}:\n${msg}!\n\nBTN1 to go back`); setWatch(showAppSettingsMenu, BTN1, { repeat: false }); } - let appSettings = storage.read(app.settings); - if (!appSettings) { - return showError('Missing settings'); - } + let appSettings = storage.read(app.id+'.settings.js'); try { appSettings = eval(appSettings); } catch (e) { diff --git a/apps/simpletimer/ChangeLog b/apps/simpletimer/ChangeLog new file mode 100644 index 000000000..e548d90fa --- /dev/null +++ b/apps/simpletimer/ChangeLog @@ -0,0 +1,5 @@ +0.01: Initial version +0.02: Reset with gesture +0.03: BTN2 to open launcher +0.04: Remember last set time +0.05: Fix buzz that doesn't stop (fix #521) diff --git a/apps/simpletimer/README.md b/apps/simpletimer/README.md new file mode 100644 index 000000000..426942034 --- /dev/null +++ b/apps/simpletimer/README.md @@ -0,0 +1,19 @@ +# Timer + +Simple timer, useful when playing board games or cooking + +## Features + +- When the time is up the timer can be reset to starting time, this is useful e.g. for playing board games +- When the countdown is running the timer cannot be adjusted, this prevents accidental time variations +- When the time is up the starting time is shown, as a reminder of the time elapsed +- When the time is up the timer can be reset with a gesture, no need to use any button + +## How to use it + +- Tap on minutes to increase them one by one +- Tap on seconds to increase them one by one +- Press BTN3 to reset time to 0 +- Press BTN1 to start the timer or reset to the original time +- Press BTN2 to return to the launcher (only while countdown is not running) +- When the time is up use the [swipeleft](https://github.com/espruino/BangleApps/tree/master/apps/gesture) gesture to reset the timer diff --git a/apps/simpletimer/app-icon.js b/apps/simpletimer/app-icon.js new file mode 100644 index 000000000..b55486dd1 --- /dev/null +++ b/apps/simpletimer/app-icon.js @@ -0,0 +1,5 @@ +require("heatshrink").decompress( + atob( + "mEwxH+AH4A/AEsxAAQso1eyrgvDrmrw4skAAQuDAAIHBrYABFsQvMGLYtGAAOAFweA2WrF4gwYFxAwEFwIvBwowFsIub64AB6wJF6wJB1mGMTFbrmsEYoADHAwAC1dhGCoTCmJhBEYoAM2RiFF6VbleBF6QABGAguSw2sgAwnCAdhXYIwBqwvT2WFDwYvP1YZCwMAlYwT1ZgORogZEqwwB1iRhBoYmGlcAYiZgOBgWFDIzCBAALESYIYvMw4ZHGCuHF5aOKeYgABYiCQMBYeyDZLzBAAQwO2QvPDhbzCeqAvbGAQQBlYvqeYIvteYMreJ7vaACbvQJxwAP1YvLGAeHF7uHFxYvDwovdwovPSDusRxgvEwwvbwwvNGAmrds4vGsOyFy+ysIvPSLqNPGDwuT/xyEwySS2QuEF6BgEYYL0Q1ZIEFyIwGMQIxM1ZcFFyYwHreFw+rSwmy1eHwoSGFygxJABwtXeo4upMSQtdGZorjAH4A/AF4A==" + ) +) diff --git a/apps/simpletimer/app.js b/apps/simpletimer/app.js new file mode 100644 index 000000000..75c118980 --- /dev/null +++ b/apps/simpletimer/app.js @@ -0,0 +1,168 @@ +let counter = 0; +let setValue = 0; +let counterInterval; +let state; +let saved = require("Storage").readJSON("simpletimer.json",true) || {}; + +const DEBOUNCE = 50; + +function buzzAndBeep() { + return Bangle.buzz(1000, 1) + .then(() => Bangle.beep(200, 3000)) + .then(() => setTimeout(buzzAndBeep, 5000)); +} + +function outOfTime() { + g.clearRect(0, 0, 220, 70); + g.setFontAlign(0, 0); + g.setFont("6x8", 3); + g.drawString("Time UP!", 120, 50); + counter = setValue; + buzzAndBeep(); + setInterval(() => { + g.clearRect(0, 70, 220, 160); + setTimeout(draw, 200); + }, 400); + state = "stopped"; +} + +function draw() { + const minutes = Math.floor(counter / 60); + const seconds = Math.floor(counter % 60); + const seconds2Digits = seconds < 10 ? `0${seconds}` : seconds.toString(); + g.clearRect(0, 70, 220, 160); + g.setFontAlign(0, 0); + g.setFont("6x8", 7); + g.drawString( + `${minutes < 10 ? "0" : ""}${minutes}:${seconds2Digits}`, + 120, + 120 + ); +} + +function countDown() { + if (counter <= 0) { + if (counterInterval) { + clearInterval(counterInterval); + counterInterval = undefined; + } + outOfTime(); + return; + } + + counter--; + draw(); +} + +function clearIntervals() { + clearInterval(); + counterInterval = undefined; +} + +function set(delta) { + if (state === "started") return; + counter += delta; + saved.counter = counter; + require("Storage").write("simpletimer.json", saved); + if (state === "unset") { + state = "set"; + } + draw(); + g.flip(); +} + +function startTimer() { + setValue = counter; + countDown(); + counterInterval = setInterval(countDown, 1000); +} + +// unset -> set -> started -> -> stopped -> set +const stateMap = { + set: () => { + state = "started"; + startTimer(); + }, + started: () => { + resetTimer(setValue); + }, + stopped: () => { + resetTimer(setValue); + } +}; + +function changeState() { + if (stateMap[state]) stateMap[state](); +} + +function drawLabels() { + g.clear(); + g.setFontAlign(-1, 0); + g.setFont("6x8", 7); + g.drawString(`+ +`, 35, 180); + g.setFontAlign(0, 0, 3); + g.setFont("6x8", 1); + g.drawString(`reset (re)start`, 230, 120); +} + +function resetTimer(value) { + clearIntervals(); + VIBRATE.reset(); // turn off vibration (clearIntervals stops the buzz turning off) + counter = value; + setValue = value; + drawLabels(); + draw(); + state = value === 0 ? "unset" : "set"; +} + +function addWatch() { + clearWatch(); + setWatch(changeState, BTN1, { + debounce: DEBOUNCE, + repeat: true, + edge: "falling" + }); + setWatch(() => { + if (state !== "started") { + Bangle.showLauncher(); + }}, + BTN2, + { + repeat: false, + edge: "falling", + }, + ); + setWatch( + () => { + resetTimer(0); + }, + BTN3, + { + debounce: DEBOUNCE, + repeat: true, + edge: "falling" + } + ); + setWatch( + () => { + set(60); + }, + BTN4, + { + debounce: DEBOUNCE, + repeat: true, + edge: "falling" + } + ); + setWatch(() => set(1), BTN5, { + debounce: DEBOUNCE, + repeat: true, + edge: "falling" + }); +} +Bangle.on("aiGesture", gesture => { + if (gesture === "swipeleft" && state === "stopped") resetTimer(0); +}); + +resetTimer(saved.counter || 0); +addWatch(); diff --git a/apps/simpletimer/app.png b/apps/simpletimer/app.png new file mode 100644 index 000000000..f593a3a8b Binary files /dev/null and b/apps/simpletimer/app.png differ diff --git a/apps/simpletimer/gesture-tfmodel.js b/apps/simpletimer/gesture-tfmodel.js new file mode 100644 index 000000000..a29901ef5 --- /dev/null +++ b/apps/simpletimer/gesture-tfmodel.js @@ -0,0 +1 @@ +atob("HAAAAFRGTDMAABIAHAAEAAgADAAQABQAAAAYABIAAAADAAAAjA0AABAEAAD4AwAAPAAAAAQAAAABAAAADAAAAAgADAAEAAgACAAAAAgAAAAMAAAAEwAAAG1pbl9ydW50aW1lX3ZlcnNpb24ADQAAALADAACIAwAAWAMAAKQBAABcAQAAVAEAAEwBAABEAQAAEAEAAAgBAAAAAQAAHAAAAAQAAACu/P//BAAAAAUAAAAxLjUuMAAAAML8//8EAAAA0gAAAMJbJV3AgRwc/Nn1I0Qd5WDwPa0nY6nMbPyvfyOWOlqqf+64Juoa5kjpQVjoHTubf/NpJEH1Sqe0/PfJ5/o08zInA5f6fyg/vRaJEX9VQE5BPlRI0EP1Imq8NkNBLz3Q1hW5k9frf1Lfuc/rEwfGJqbG/txEf35Ey0jgICJ/B+vyu1FF8M+HA2ZcLhAX+QGB26MS3iLLDxnLNlvp9jbo8gM/5YEc0RoWA+W+Ih9T3AyBSNRX4Ew+739Y9R3p+cnS/dj283/BrQDWUu/y4Q8JAwj+5QAA4Pz//+T8//+q/f//BAAAACQAAABejWTlyU3qNn6j53/W2AR0lmjJ9d87YN1cNbBDobHjz5gdMFIY/f//HP3//yD9///m/f//BAAAADgAAADB////e////zwAAACt////5P////3///8yAAAAmP///53///9K////SP///2H///+J////c////yr+//8EAAAApAEAAA4mHQIO1TUu59UbG4FFDeDwNN3sEtUHD18IISYb5aXfCQ0g6/wWDMADFirm8M7t9f4H1eMQluL9Btze72b+5wXX08vbHvLxET4L+xHtFeHZ5NfHV/zUByIHzTf/rxUS28LqwaXnhn8izicXm7z7t+Ja6dHaVL8zE6oR6TwY3LUxFktGE/DcDQz71rkc9SrmL+zs6+3/yTse/xvcHcsIgenD5OHuJeT199TsxRCi6bVGzgb579Xj2vTt2g/RqTAbAsroB9oAtgbn7AkS8fEJ0O8x/nML+1Xf/cAqK8Yo9yvVIjztKSQT+NH09AdCIb/6Af/VD9+EI+vvKuvEEk9h5k8PtNrNIucw/xGBFVzOCQ3q/wH+BBtoCOf74smpLzb37xcvFlcQEPAMmP4o9+L5JU8QMgHG5wrINjRx8/UnPBc57cvo79oGAUzs5jTzFWznEvzP6s8Wf+gQHOn2QAYD/hE8Fuw45P8B0y0GCgr4AyrsAgjRH0XpGRM0+gD9YPoB++3wM/TcDn+fDf1lAAoaCtP4M/3kbQvrATrd6g/y7/rv6Kwj3Nr///8EAAAAGAAAAAYBAADiAQAA2P///5f+//+6////Mf///wAABgAIAAQABgAAAAQAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaP///w8AAABUT0NPIENvbnZlcnRlZC4AAQAAAAQAAAD09v//3AEAANABAADEAQAABAAAAAYAAACYAQAAQAEAANgAAACEAAAAOAAAAAQAAACK/v//BAAAABAAAAAEAAAAAQAAAAwAAAABAAAAAAAAAAAADgAYAAgADAAQAAcAFAAOAAAAAAAACAEAAAAcAAAAEAAAAAgAAAAEAAQABAAAAAEAAAAAAAAAAwAAAAoAAAAJAAAAAQAAAAAADgAaAAgADAAQAAcAFAAOAAAAAAAABQIAAAA8AAAAMAAAABQAAAAAAA4AGAAHAAgADAAQABQADgAAAAAAAAEBAAAALgAAAAEAAAAuAAAAAQAAAAoAAAABAAAACAAAAKr///8AAAABPAAAADAAAAAUAAAAEAAYAAAACAAMAAcAEAAUABAAAAAAAAABAQAAAAEAAAACAAAAAgAAAAEAAAAIAAAAAwAAAAUAAAAGAAAABwAAAAAADgAUAAAACAAMAAcAEAAOAAAAAAAAATAAAAAkAAAAEAAAAAwAEAAGAAgADAAHAAwAAAAAAAEBAQAAAAEAAAABAAAABQAAAAMAAAACAAAAAwAAAAQAAAAAAAoAEAAEAAgADAAKAAAAAwAAABAAAAAEAAAAAQAAAAIAAAABAAAACwAAAAEAAAAMAAAAAQAAAAsAAAANAAAAEAcAAJwGAAAcBgAAAAUAAPwDAAB4AwAAvAIAABgCAACMAQAACAEAAHQAAAA8AAAABAAAANj///8YAAAABAAAAAgAAABJZGVudGl0eQAAAAACAAAAAQAAAAYAAAAMAAwABAAAAAAACAAMAAAAHAAAAAQAAAAMAAAAYWNjZWxlcmF0aW9uAAAAAAQAAAABAAAAMgAAAAEAAAADAAAAmvn//wAAAAl0AAAABgAAAEQAAAAEAAAAjPn//zAAAAAkAAAAGAAAAAQAAAABAAAAgP////////8AAAAAAQAAAN6l9z4BAAAAOK72QgEAAAAAAAAAIAAAAHNlcXVlbnRpYWwvbWF4X3Bvb2xpbmcyZC9NYXhQb29sAAAAAAQAAAABAAAAAQAAAAEAAAAGAAAAKvr//wAAAAlsAAAACAAAACwAAAAEAAAAjPr//xgAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAEAAABVoaw7MAAAAHNlcXVlbnRpYWwvZGVuc2UvTWF0TXVsL1JlYWRWYXJpYWJsZU9wL3RyYW5zcG9zZQAAAAACAAAABgAAAAYAAACq+v//AAAACWwAAAAJAAAARAAAAAQAAACc+v//MAAAACQAAAAYAAAABAAAAAEAAACA/////////wAAAAABAAAA3qX3PgEAAAA4rvZCAQAAAAAAAAAYAAAAc2VxdWVudGlhbC9jb252MmRfMS9SZWx1AAAAAAQAAAABAAAALgAAAAEAAAAGAAAAMvv//wAAAAKQAAAAAgAAAGQAAAAEAAAAlPv//zwAAAAEAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAABUbvA6FaemOke74Do4TZA6gTLYOpTt+zofAAAAc2VxdWVudGlhbC9jb252MmRfMS9Db252MkRfYmlhcwABAAAABgAAANL7//8AAAAJnAAAAAMAAABkAAAABAAAADT8//88AAAABAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAQ3uTO3hzTDv12Yk71QcxO86dhDuqiJo7KQAAAHNlcXVlbnRpYWwvY29udjJkXzEvQ29udjJEL1JlYWRWYXJpYWJsZU9wAAAABAAAAAYAAAAFAAAAAQAAAA4AAACK/P//AAAACWQAAAAHAAAAQAAAAAQAAAB8/P//LAAAACAAAAAUAAAABAAAAAEAAACA/////////wEAAADfq9A+AQAAADPbz0IBAAAAAAAAABYAAABzZXF1ZW50aWFsL2NvbnYyZC9SZWx1AAAEAAAAAQAAAC4AAAABAAAADgAAAAr9//8AAAAC8AAAAAQAAADEAAAABAAAAGz9//98AAAABAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAIieCjtEoPM6zIP5OgV3xjosFgQ7+qsTOwl55zpbKvM6YZ8XO+0qyjoJ/CM7Eq0SO2aMIDuFGvM6HQAAAHNlcXVlbnRpYWwvY29udjJkL0NvbnYyRF9iaWFzAAAAAQAAAA4AAAAK/v//AAAACfwAAAALAAAAyAAAAAQAAABs/v//gAAAAAQAAAAOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAqzQ2O3QdIDs6/CM7Nm8CO3aeLTvLGkI7syAYO/bPHzs3TEc7Md4EO/GLVzu9y0A7uAdTO43FHzsnAAAAc2VxdWVudGlhbC9jb252MmQvQ29udjJEL1JlYWRWYXJpYWJsZU9wAAQAAAAOAAAABQAAAAEAAAADAAAAIv///wAAAAlgAAAACgAAAEAAAAAEAAAAFP///ywAAAAgAAAAFAAAAAQAAAABAAAABwAAAAAAAAABAAAAw8JCPwEAAAAAALZCAQAAAAAAzsIRAAAAYWNjZWxlcmF0aW9uX2ludDgAAAAEAAAAAQAAADIAAAABAAAAAwAAAJ7///8AAAACUAAAAAEAAAA0AAAAEAAAAAwADAAAAAAABAAIAAwAAAAUAAAABAAAAAEAAAAAAAAAAAAAAAEAAACD/yY7DQAAAElkZW50aXR5X2JpYXMAAAABAAAABgAAAAAADgAYAAgABwAMABAAFAAOAAAAAAAACWgAAAAFAAAATAAAABAAAAAMABQABAAIAAwAEAAMAAAALAAAACAAAAAUAAAABAAAAAEAAAAJAAAAAAAAAAEAAACacSU/AQAAALcXmUIBAAAAmoCwwg0AAABJZGVudGl0eV9pbnQ4AAAAAgAAAAEAAAAGAAAABQAAAGAAAABEAAAAKAAAABwAAAAEAAAA1v///wAAAAYCAAAAAAAGAAgABwAGAAAAAAAAcvL///8AAAARAgAAAAAACgAOAAcAAAAIAAoAAAAAAAAJBAAAAAAACgAMAAcAAAAIAAoAAAAAAAADAwAAAA==") diff --git a/apps/simpletimer/gesture-tfnames.js b/apps/simpletimer/gesture-tfnames.js new file mode 100644 index 000000000..ba0d58546 --- /dev/null +++ b/apps/simpletimer/gesture-tfnames.js @@ -0,0 +1 @@ +"swipeleft,swiperight,upup,waggle,clap2" diff --git a/apps/sleepphasealarm/ChangeLog b/apps/sleepphasealarm/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/sleepphasealarm/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/sleepphasealarm/app-icon.js b/apps/sleepphasealarm/app-icon.js new file mode 100644 index 000000000..3fbcc29af --- /dev/null +++ b/apps/sleepphasealarm/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AH4AfhGIxGAC9YABxBIWF05ZCCYRfRC65CCLSoqBOKwutO4oAK7vd6AXbACAXz93uC6kOC4PgC6YWBAAMCkQAJkAXWkQX2O4YXTU4YXS6czAAUyC/4XBACIX/C8rXBABkNC/4XNAH4A/ABoA=")) diff --git a/apps/sleepphasealarm/app.js b/apps/sleepphasealarm/app.js new file mode 100644 index 000000000..1f8bf92ae --- /dev/null +++ b/apps/sleepphasealarm/app.js @@ -0,0 +1,137 @@ +const alarms = require("Storage").readJSON("alarm.json",1)||[]; +const active = alarms.filter(a=>a.on); + +// Sleep/Wake detection with Estimation of Stationary Sleep-segments (ESS): +// Marko Borazio, Eugen Berlin, Nagihan Kücükyildiz, Philipp M. Scholl and Kristof Van Laerhoven, "Towards a Benchmark for Wearable Sleep Analysis with Inertial Wrist-worn Sensing Units", ICHI 2014, Verona, Italy, IEEE Press, 2014. +// https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en +// +// Function needs to be called for every measurement but returns a value at maximum once a second (see winwidth) +// start of sleep marker is delayed by sleepthresh due to continous data reading +const winwidth=13; +const nomothresh=0.006; +const sleepthresh=600; +var ess_values = []; +var slsnds = 0; +function calc_ess(val) { + ess_values.push(val); + + if (ess_values.length == winwidth) { + // calculate standard deviation over ~1s + const mean = ess_values.reduce((prev,cur) => cur+prev) / ess_values.length; + const stddev = Math.sqrt(ess_values.map(val => Math.pow(val-mean,2)).reduce((prev,cur) => prev+cur)/ess_values.length); + ess_values = []; + + // check for non-movement according to the threshold + const nonmot = stddev < nomothresh; + + // amount of seconds within non-movement sections + if (nonmot) { + slsnds+=1; + if (slsnds >= sleepthresh) { + return true; // awake + } + } else { + slsnds=0; + return false; // sleep + } + } +} + +// locate next alarm +var nextAlarm; +active.forEach(alarm => { + const now = new Date(); + const alarmHour = alarm.hr/1; + const alarmMinute = Math.round((alarm.hr%1)*60); + var dateAlarm = new Date(now.getFullYear(), now.getMonth(), now.getDate(), alarmHour, alarmMinute); + if (dateAlarm < now) { // dateAlarm in the past, add 24h + dateAlarm.setTime(dateAlarm.getTime() + (24*60*60*1000)); + } + if (nextAlarm === undefined || dateAlarm < nextAlarm) { + nextAlarm = dateAlarm; + } +}); + +function drawString(s, x, y) { + g.clearRect(0,y-15,239,y+15); + g.reset(); + g.setFont("Vector",20); + g.setFontAlign(0,0); // align right bottom + g.drawString(s, x, y); +} + +function drawApp() { + g.clearRect(0,24,239,215); + var alarmHour = nextAlarm.getHours(); + var alarmMinute = nextAlarm.getMinutes(); + if (alarmHour < 10) alarmHour = "0" + alarmHour; + if (alarmMinute < 10) alarmMinute = "0" + alarmMinute; + const s = alarmHour + ":" + alarmMinute + "\n\n"; + E.showMessage(s, "Sleep Phase Alarm"); + + function drawTime() { + if (Bangle.isLCDOn()) { + const now = new Date(); + var nowHour = now.getHours(); + var nowMinute = now.getMinutes(); + var nowSecond = now.getSeconds(); + if (nowHour < 10) nowHour = "0" + nowHour; + if (nowMinute < 10) nowMinute = "0" + nowMinute; + if (nowSecond < 10) nowSecond = "0" + nowSecond; + const time = nowHour + ":" + nowMinute + ":" + nowSecond; + drawString(time, 120, 140); + } + } + + setInterval(drawTime, 500); // 2Hz +} + +var buzzCount = 19; +function buzz() { + Bangle.setLCDPower(1); + Bangle.buzz().then(()=>{ + if (buzzCount--) { + setTimeout(buzz, 500); + } else { + // back to main after finish + setTimeout(load, 1000); + } + }); +} + +// run +var minAlarm = new Date(); +var measure = true; +if (nextAlarm !== undefined) { + Bangle.drawWidgets(); + Bangle.loadWidgets(); + + // minimum alert 30 minutes early + minAlarm.setTime(nextAlarm.getTime() - (30*60*1000)); + setInterval(function() { + const now = new Date(); + const acc = Bangle.getAccel().mag; + const swest = calc_ess(acc); + + if (swest !== undefined) { + if (Bangle.isLCDOn()) { + drawString(swest ? "Sleep" : "Awake", 120, 180); + } + } + + if (now >= nextAlarm) { + // The alarm widget should handle this one + setTimeout(load, 1000); + } else if (measure && now >= minAlarm && swest === false) { + buzz(); + measure = false; + } + }, 80); // 12.5Hz + drawApp(); +} else { + E.showMessage('No Alarm'); + setTimeout(load, 1000); +} +// BTN2 to menu, BTN3 to main +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +setWatch(() => load(), BTN3, { repeat: false, edge: "falling" }); diff --git a/apps/sleepphasealarm/app.png b/apps/sleepphasealarm/app.png new file mode 100644 index 000000000..0a19bd463 Binary files /dev/null and b/apps/sleepphasealarm/app.png differ diff --git a/apps/slevel/ChangeLog b/apps/slevel/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/slevel/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/smtswch/ChangeLog b/apps/smtswch/ChangeLog new file mode 100644 index 000000000..6d3bcf353 --- /dev/null +++ b/apps/smtswch/ChangeLog @@ -0,0 +1 @@ +0.01: New App! See the README.MD for details on how to use it. \ No newline at end of file diff --git a/apps/smtswch/README.md b/apps/smtswch/README.md new file mode 100644 index 000000000..3ac6658c9 --- /dev/null +++ b/apps/smtswch/README.md @@ -0,0 +1,72 @@ +# Smart Switch app for BangleJS + +This app allows you to remotely control devices (or anything else you like!) with: + +* [Bangle.js](https://www.espruino.com/Bangle.js) (Hackable JavaScript Smartwatch) +* [EspruinoHub](https://github.com/espruino/EspruinoHub) (Bluetooth Low Energy -> MQTT bridge) +* [Node-RED](https://nodered.org) (Flow-based programming tool) + +![Demo of Smart Switch app in action](https://raw.githubusercontent.com/wdmtech/BangleApps/add-video/apps/smtswch/demo.gif) + +* Swipe right to turn a device ON +* Swipe left to turn a device OFF +* BTN1 (top-right) - Previous device (page) +* BTN3 (bottom-right) - Next device (page) + +> Currently, devices can only be added/removed/changed by editing them in the app's source code. + +# How to use + +First, you'll need a device that supports BLE. + +Install EspruinoHub following the directions at [https://github.com/espruino/EspruinoHub](https://github.com/espruino/EspruinoHub) +Install [Node-RED](https://nodered.org/docs/getting-started) + +## Example Node-RED flow + +Import the following JSON into Node-RED and configure the MQTT IN node to use your EspruinoHub's MQTT instance (default port is 1883): + +```JSON +[{"id":"87c6f73e.f22038","type":"mqtt in","z":"a256522.ca0b0b","name":"⌚️BangleJS data","topic":"/ble/advertise/ec:5a:c1:a7:fc:91/data","qos":"2","datatype":"auto","broker":"b961407a.91beb","x":860,"y":100,"wires":[["c37809de.3fc538"]]},{"id":"c37809de.3fc538","type":"function","z":"a256522.ca0b0b","name":"Set topic, remove quotes","func":"msg.topic = \"any_topic_here\";\nmsg.payload = msg.payload.replace(/['\"]+/g, \"\")\n\nreturn msg;","outputs":1,"noerr":0,"x":1070,"y":100,"wires":[["9019be89.5b6d5"]]},{"id":"9019be89.5b6d5","type":"debug","z":"a256522.ca0b0b","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1250,"y":100,"wires":[]},{"id":"b961407a.91beb","type":"mqtt-broker","z":"","name":"","broker":"192.168.1.22","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"hello_there","birthQos":"0","birthPayload":"","closeTopic":"bye_now","closeQos":"0","closePayload":"true","willTopic":"bye_now","willQos":"0","willPayload":"true"}] +``` + +Replace the topic of the MQTT IN node to use the ID of your Bangle.js device, e.g: + +`/ble/advertise/ec:5a:c1:a7:fc:91/data` + +Once you see the MQTT IN node is configured correctly (it says `connected` below the node itself), try swiping in the Smart Switch app, and +you should see some data in the Debug node. + +The possibilities for switching things on and off via Bangle.js are now endless. Have fun! + +# How it works + +This is the code that does the actual [BLE advertising](https://www.espruino.com/BLE%20Advertising) on the watch itself: + +```JS +NRF.setAdvertising({ + 0xFFFF: [currentPage, page.state] +}); +``` + +# Not working? + +If you can't see any data in Node-RED after swiping, check to see if your device is advertising by visiting port 1888 of your EspruinoHub instance: + +You should see something like the following: + +``` +ec:5a:c1:a7:fc:91 - Bangle.js fc91 (RSSI -83) + ffff => {"data":"1,1"} +``` + +# Any comments? + +[Tweet me!](https://twitter.com/BillyWhizzkid) + +# Future + +PRs welcome! + +[ ] Add an HTML GUI for configuring devices inside the Bangle.js App Loader +[ ] Allow enable/disable of buzz/beep on change of device state diff --git a/apps/smtswch/app-icon.js b/apps/smtswch/app-icon.js new file mode 100644 index 000000000..9153bd3ca --- /dev/null +++ b/apps/smtswch/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AH4A/AH4A/AH4Ag1gAECyGFAB1bAAmAFooyQFp4uGEoWIwQAEGBgtQFwtcFpAACxAwJFyIvFEAItIMAowFF1IwFF6zqBRhIvIxBetMAYvWdgJeSAAOHFyQvEw5eRBAeIF6+IF5wIHF66+LTJIvlNBaPfRRAved4g0BAASNJd4f+F61cFQYAEFxQ/Bw4vXYAQAFLxms/wABGC2ALyaOBF7BgGLyAweFyIwTF4jyDLxKMBFw4xTGAhhEFpAuKGKQwFeg4ADFxgAZFlgA/AH4A/AH4A/AH4A/AH4AhA")) \ No newline at end of file diff --git a/apps/smtswch/app.js b/apps/smtswch/app.js new file mode 100644 index 000000000..e8491a065 --- /dev/null +++ b/apps/smtswch/app.js @@ -0,0 +1,79 @@ + +// Learn more! +// https://www.espruino.com/Reference#l_NRF_setAdvertising +// https://www.espruino.com/Bangle.js#buttons + +// Initial graphics setup +g.clear(); +g.setFontAlign(0, 0); // center font +// g.setFont("6x8", 8); // bitmap font, 8x magnified +g.setFont("Vector", 40); // vector font, 80px + +// Let the app begin! +const storage = require("Storage"); + +let currentPage = 0; +let pages = [ + { + name: "Downstairs", + icon: "light", + state: false + }, + { + name: "Upstairs", + icon: "switch", + state: false + }]; + +function loadPage(page) { + const icon = page.state ? page.icon + "-on" : page.icon + "-off"; + Bangle.beep(); + g.clear(); + g.setFont("Vector", 10); + g.drawString("prev", g.getWidth() - 25, 20); + g.drawString("next", g.getWidth() - 25, 220); + g.setFont("Vector", 15); + g.drawString(page.name, g.getWidth() / 2, 200); + g.setFont("Vector", 40); + g.drawString(page.state ? "On" : "Off", g.getWidth() / 2, g.getHeight() / 2); + g.drawImage(storage.read(`${icon}.img`), g.getWidth() / 2 - 24, g.getHeight() / 2 - 24 - 50); +} + +function prevPage() { + if (currentPage > 0) { + currentPage--; + loadPage(pages[currentPage]); + } +} + +function nextPage() { + if (currentPage < pages.length - 1) { + currentPage++; + loadPage(pages[currentPage]); + } +} + +function swipe(dir) { + + const page = pages[currentPage]; + + page.state = dir == 1; + + NRF.setAdvertising({ + 0xFFFF: [currentPage, page.state] + }); + + loadPage(page); + + // optional - this keeps the watch LCD lit up + g.flip(); + + Bangle.buzz(); +} + +Bangle.on('swipe', swipe); + +setWatch(prevPage, BTN, {edge: "rising", debounce: 50, repeat: true}); +setWatch(nextPage, BTN3, {edge: "rising", debounce: 50, repeat: true}); + +loadPage(pages[currentPage]); \ No newline at end of file diff --git a/apps/smtswch/app.png b/apps/smtswch/app.png new file mode 100644 index 000000000..9ed00c6b6 Binary files /dev/null and b/apps/smtswch/app.png differ diff --git a/apps/smtswch/light-off.js b/apps/smtswch/light-off.js new file mode 100644 index 000000000..c6e6b7e77 --- /dev/null +++ b/apps/smtswch/light-off.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AGeJAAwttGMotLGMQiD1uzAAWtGEgtE64ACF5IwbFwYtESUouGFpowaFywvXDIS7CFyIwXLwouSF6peF1ovrRqowWF4heEstlApIveDolfAAIEGF76OGFYQuMF6+zdo4uOF6+tF49lFwK9KF7AAJLxovUGBiOhF+IwLF5guWF+AwKF5YuYGBQvKFzQwJF5IucGBAvIFzwwHF44ugF+AwFF4wui/2CABQvrr1YAAIvjrwoDAAwvjFhFeR8onDX/4vcXxIvkYA73BR0gACYA4umMI4uoGAouqAH4AK")) \ No newline at end of file diff --git a/apps/smtswch/light-on.js b/apps/smtswch/light-on.js new file mode 100644 index 000000000..a3e7c322f --- /dev/null +++ b/apps/smtswch/light-on.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AT5gAGFtoxlFpYxhFp4xeFyYwaFyowZF9wuXGC4vuFzIwVF9wdK53OApIwYDRHN6gAC5oFFF8QoC5wyIMRAvZ5wkERgJbCBQqPfEoKGGL4S/j5i3GFwS/jK5BnIF6owMW4S8KFygvKSIQDFF85bBF8QwKF54uUF+AwJF5wuWF+AwIF5ouYGBAvMFzQwHF5YucGAwvKFzwwFF5IugAAOCAA1erAABF0X+rwoDAAwvjFhFeMYIvkE4QAHF8a/vwS+JF8jAHe4KOkGAaQFroumAAUrAAQtpGAgusAH4A/AFI=")) \ No newline at end of file diff --git a/apps/smtswch/switch-off.js b/apps/smtswch/switch-off.js new file mode 100644 index 000000000..58e6e94e6 --- /dev/null +++ b/apps/smtswch/switch-off.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AH4A/AH4A/AH4AI1gAEFlgAEz2WAAm6ABwuPxGCAAgJC0wwVGJQtIAAWIGIWXF6gxIEAItIMAgABMCowGFyKSGGCulRhQvHegovVLySRGF6QwBLyjyaF4IuQBAaQX3WmF5wIG0ovXXxaZJYDLuMF8SPHRRCPed4mIcwaNJd7YvBAA4uKH4OXF63+/wuHLxi+YF4JgHLxiOXFwJgHLxmmFwYvXGAqNQFzAwELxKMBdjQwJMAwtCRgovRFpDDIAAjqEFyItLGRQWQAH4A/AH4A/AH4A/AH4A/AH4AP")) \ No newline at end of file diff --git a/apps/smtswch/switch-on.js b/apps/smtswch/switch-on.js new file mode 100644 index 000000000..9153bd3ca --- /dev/null +++ b/apps/smtswch/switch-on.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AH4A/AH4A/AH4Ag1gAECyGFAB1bAAmAFooyQFp4uGEoWIwQAEGBgtQFwtcFpAACxAwJFyIvFEAItIMAowFF1IwFF6zqBRhIvIxBetMAYvWdgJeSAAOHFyQvEw5eRBAeIF6+IF5wIHF66+LTJIvlNBaPfRRAved4g0BAASNJd4f+F61cFQYAEFxQ/Bw4vXYAQAFLxms/wABGC2ALyaOBF7BgGLyAweFyIwTF4jyDLxKMBFw4xTGAhhEFpAuKGKQwFeg4ADFxgAZFlgA/AH4A/AH4A/AH4A/AH4AhA")) \ No newline at end of file diff --git a/apps/speedo/ChangeLog b/apps/speedo/ChangeLog new file mode 100644 index 000000000..35cef4520 --- /dev/null +++ b/apps/speedo/ChangeLog @@ -0,0 +1,5 @@ +0.01: New App! +0.02: Add widgets to app +0.03: Use offscreen buffer (not doublebuffer) + Use 'locale' to get internationalised speed +0.04: Start GPS after loading app, just in case widgets affect it (#449) diff --git a/apps/speedo/speedo.js b/apps/speedo/speedo.js index 2fada429a..174702d71 100644 --- a/apps/speedo/speedo.js +++ b/apps/speedo/speedo.js @@ -1,24 +1,33 @@ -Bangle.setGPSPower(1); -Bangle.setLCDMode("doublebuffered"); +var buf = Graphics.createArrayBuffer(240,120,1,{msb:true}); var lastFix = {fix:0,satellites:0}; function onGPS(fix) { lastFix = fix; - g.clear(); - g.setFontAlign(0,0); - g.setFont("6x8"); - g.drawString(fix.satellites+" satellites",120,6); + buf.clear(); + buf.setFontAlign(0,0); + buf.setFont("6x8"); + buf.drawString(fix.satellites+" satellites",120,6); if (fix.fix) { + var speed = require("locale").speed(fix.speed); + var m = speed.match(/([0-9,\.]+)(.*)/); // regex splits numbers from units var txt = (fix.speed<20) ? fix.speed.toFixed(1) : Math.round(fix.speed); + var value = m[1], units = m[2]; var s = 80; - g.setFontVector(s); - g.drawString(txt,120,80); - g.setFont("6x8",2); - g.drawString("km/h",120,80+16+s/2); + buf.setFontVector(s); + buf.drawString(value,120,10+s/2); + buf.setFont("6x8",2); + buf.drawString(units,120,s+26); } else { - g.setFont("6x8",2); - g.drawString("Waiting for GPS",120,80); + buf.setFont("6x8",2); + buf.drawString("Waiting for GPS",120,56); } + g.reset(); + g.drawImage({width:buf.getWidth(),height:buf.getHeight(),bpp:1,buffer:buf.buffer},0,70); g.flip(); } +g.clear(); onGPS(lastFix); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + Bangle.on('GPS', onGPS); +Bangle.setGPSPower(1); diff --git a/apps/stetho/ChangeLog b/apps/stetho/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/stetho/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/stetho/stetho.js b/apps/stetho/stetho.js index ec0916f4e..6fee91c12 100644 --- a/apps/stetho/stetho.js +++ b/apps/stetho/stetho.js @@ -11,8 +11,8 @@ var hrm; var SPEAKER_PIN = D18; function freq(f) { - console.log("frequency: ", f); - if (f===0) digitalWrite(SPEAKER_PIN, 0); + console.log("frequency: ", f); + if (f===0) digitalWrite(SPEAKER_PIN, 0); else analogWrite(SPEAKER_PIN, 0.5, {freq: f}); } diff --git a/apps/svclock/ChangeLog b/apps/svclock/ChangeLog new file mode 100644 index 000000000..a9e0036a3 --- /dev/null +++ b/apps/svclock/ChangeLog @@ -0,0 +1 @@ +0.01: Modification of SimpleClock 0.04 to use Vectorfont diff --git a/apps/svclock/vclock-simple-icon.js b/apps/svclock/vclock-simple-icon.js new file mode 100644 index 000000000..b41bd6fcc --- /dev/null +++ b/apps/svclock/vclock-simple-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4ATiwAGFdYzlFp4xeFyYwZD49kxGt2fX6+z1uIsgxcDQtAxArCAA+zxFAGDAYFxAsJAAuIGCxcF1ouPAAOsGCouERRSUKSYguoGARgRCIiMSAAutGCDqUABNkF5yNEFzKRQLzwABxAvRdgYFBDgYFFBphgEF5lkEJwNOYIaORF7KQMBYetEJoDHAo+sF56+DF7TAMBYaBQBpwv/R97vvxCPdxAvLGAdkF7tkFxbAIF7C+MSBQAXRxovEoAvboAvNMD69DFxYvEi2sFy+sDwgvLGAryDACTsEFxrCGGCmzXh5gJSSaMFF6AwGshiPdQguSGA8WxAxK2eIRYguUGBBjBxGsGYWz1mILYwuWGJQANFq4wWFzQxSFrozNFcYA/AH4Av")) diff --git a/apps/svclock/vclock-simple.js b/apps/svclock/vclock-simple.js new file mode 100644 index 000000000..2af8b74a4 --- /dev/null +++ b/apps/svclock/vclock-simple.js @@ -0,0 +1,84 @@ +/* jshint esversion: 6 */ +const timeFontSize = 65; +const dateFontSize = 20; +const gmtFontSize = 10; +const font = "Vector"; + +const xyCenter = g.getWidth() / 2; +const yposTime = 75; +const yposDate = 130; +const yposYear = 175; +const yposGMT = 220; + +// Check settings for what type our clock should be +var is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; + +function drawSimpleClock() { + g.clear(); + Bangle.drawWidgets(); + + // get date + var d = new Date(); + var da = d.toString().split(" "); + + g.reset(); // default draw styles + // drawSting centered + g.setFontAlign(0, 0); + + // draw time + var time = da[4].substr(0, 5).split(":"); + var hours = time[0], + minutes = time[1]; + var meridian = ""; + if (is12Hour) { + hours = parseInt(hours,10); + meridian = "AM"; + if (hours == 0) { + hours = 12; + meridian = "AM"; + } else if (hours >= 12) { + meridian = "PM"; + if (hours>12) hours -= 12; + } + hours = (" "+hours).substr(-2); + } + + g.setFont(font, timeFontSize); + g.drawString(`${hours}:${minutes}`, xyCenter, yposTime, true); + g.setFont(font, gmtFontSize); + g.drawString(meridian, xyCenter + 102, yposTime + 10, true); + + // draw Day, name of month, Date + var date = [da[0], da[1], da[2]].join(" "); + g.setFont(font, dateFontSize); + + g.drawString(date, xyCenter, yposDate, true); + + // draw year + g.setFont(font, dateFontSize); + g.drawString(d.getFullYear(), xyCenter, yposYear, true); + + // draw gmt + var gmt = da[5]; + g.setFont(font, gmtFontSize); + g.drawString(gmt, xyCenter, yposGMT, true); +} + +// handle switch display on by pressing BTN1 +Bangle.on('lcdPower', function(on) { + if (on) drawSimpleClock(); +}); + +// clean app screen +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +// refesh every 15 sec +setInterval(drawSimpleClock, 15E3); + +// draw now +drawSimpleClock(); + +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); diff --git a/apps/svclock/vclock-simple.png b/apps/svclock/vclock-simple.png new file mode 100644 index 000000000..824062aed Binary files /dev/null and b/apps/svclock/vclock-simple.png differ diff --git a/apps/swatch/ChangeLog b/apps/swatch/ChangeLog index 9a037fa41..caa74a1ba 100644 --- a/apps/swatch/ChangeLog +++ b/apps/swatch/ChangeLog @@ -6,3 +6,4 @@ 0.04: Changed save file filename, add interface.html to allow laps to be loaded 0.05: Added widgets 0.06: Added total running time, moved lap time to smaller display, total run time now appends as first entry in array, saving now saves last lap as well +0.07: Ensure seconds counter is in sync with subseconds (fix #341) diff --git a/apps/swatch/interface.html b/apps/swatch/interface.html index 45391fb6e..1b239da3b 100644 --- a/apps/swatch/interface.html +++ b/apps/swatch/interface.html @@ -5,7 +5,7 @@ <body> <div id="records"></div> - <script src="../../lib/interface.js"></script> + <script src="../../core/lib/interface.js"></script> <script> var domRecords = document.getElementById("records"); diff --git a/apps/swatch/stopwatch.js b/apps/swatch/stopwatch.js index 659f0606d..91082e22a 100644 --- a/apps/swatch/stopwatch.js +++ b/apps/swatch/stopwatch.js @@ -83,8 +83,8 @@ setWatch(function() { // Start/stop Bangle.beep(); if (started) tStart = Date.now()+tStart-tCurrent; - tTotal = Date.now()+tTotal-tCurrent; - tCurrent = Date.now(); + tTotal = Date.now()+tTotal-tCurrent; + tCurrent = Date.now(); if (displayInterval) { clearInterval(displayInterval); displayInterval = undefined; @@ -94,7 +94,8 @@ setWatch(function() { // Start/stop displayInterval = setInterval(function() { var last = tCurrent; if (started) tCurrent = Date.now(); - if (Math.floor(last/1000)!=Math.floor(tCurrent/1000)) + if (Math.floor((last-tStart)/1000)!=Math.floor((tCurrent-tStart)/1000) || + Math.floor((last-tTotal)/1000)!=Math.floor((tCurrent-tTotal)/1000)) drawsecs(); else drawms(); diff --git a/apps/tabata/ChangeLog b/apps/tabata/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/tabata/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/torch/ChangeLog b/apps/torch/ChangeLog index 5560f00bc..8e76b717a 100644 --- a/apps/torch/ChangeLog +++ b/apps/torch/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Change start sequence to BTN1/3/1/3 to avoid accidental turning on (fix #342) diff --git a/apps/torch/widget.js b/apps/torch/widget.js index e3d1ea22f..08c94fad8 100644 --- a/apps/torch/widget.js +++ b/apps/torch/widget.js @@ -1,18 +1,26 @@ -var clickTimes = []; -var CLICK_COUNT = 4; // number of taps -var CLICK_PERIOD = 1; // second +(function() { + var clickTimes = []; + var clickPattern = ""; + var TAPS = 4; // number of taps + var PERIOD = 1; // seconds -// we don't actually create/draw a widget here at all... - -Bangle.on("lcdPower",function(on) { + // we don't actually create/draw a widget here at all... + Bangle.on("lcdPower",function(on) { // First click (that turns LCD on) isn't given to // setWatch, so handle it here - if (on) clickTimes=[getTime()]; -}); -setWatch(function(e) { - while (clickTimes.length>=CLICK_COUNT) clickTimes.shift(); - clickTimes.push(e.time); - var clickPeriod = e.time-clickTimes[0]; - if (clickTimes.length==CLICK_COUNT && clickPeriod<CLICK_PERIOD) - load("torch.app.js"); -}, BTN3, {repeat:true, edge:"rising"}); + if (!on) return; + clickTimes=[getTime()]; + clickPattern="x"; + }); + function tap(e,c) { + clickPattern = clickPattern.substr(-3)+c; + while (clickTimes.length>=TAPS) clickTimes.shift(); + clickTimes.push(e.time); + var clickPeriod = e.time-clickTimes[0]; + if (clickPeriod<PERIOD && clickPattern.match(/.313/)) { + load("torch.app.js"); + } + } + setWatch(function(e) { tap(e,"1"); }, BTN1, {repeat:true, edge:"rising"}); + setWatch(function(e) { tap(e,"3"); }, BTN3, {repeat:true, edge:"rising"}); +})(); diff --git a/apps/toucher/ChangeLog b/apps/toucher/ChangeLog index 0c97d9e13..494110d55 100644 --- a/apps/toucher/ChangeLog +++ b/apps/toucher/ChangeLog @@ -3,4 +3,4 @@ 0.03: Close launcher when lcd turn off 0.04: Complete rewrite to add animation and loop ( issue #210 ) 0.05: Improve perf -0.06: Only store relevant app data (saves RAM when many apps) +0.06: Complete rewrite in 80x80, better perf, add settings \ No newline at end of file diff --git a/apps/toucher/app.js b/apps/toucher/app.js index cf7d5333b..455a29c5d 100644 --- a/apps/toucher/app.js +++ b/apps/toucher/app.js @@ -1,160 +1,206 @@ -Bangle.setLCDMode("120x120"); +const Storage = require("Storage"); +const filename = 'toucher.json'; +let settings = Storage.readJSON(filename,1) || { + hightres: true, + animation : true, + frame : 3, + debug: false +}; + +if(!settings.highres) Bangle.setLCDMode("80x80"); +else Bangle.setLCDMode(); + g.clear(); g.flip(); -const Storage = require("Storage"); - -function getApps(){ - return Storage.list(/\.info$/).map(app=>{var a=Storage.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src,version:a.version}}) - .filter(app=>app && (app.type=="app" || app.type=="clock" || !app.type)) - .sort((a,b)=>{ - var n=(0|a.sortorder)-(0|b.sortorder); - if (n) return n; // do sortorder first - if (a.name<b.name) return -1; - if (a.name>b.name) return 1; - return 0; - }); -} +let icons = {}; const HEIGHT = g.getHeight(); const WIDTH = g.getWidth(); const HALF = WIDTH/2; -const ANIMATION_FRAME = 4; -const ANIMATION_STEP = HALF / ANIMATION_FRAME; +const ORIGINAL_ICON_SIZE = 48; + +const STATE = { + settings_open: false, + index: 0, + target: 240, + offset: 0 +}; function getPosition(index){ return (index*HALF); } -let current_app = 0; -let target = 0; -let slideOffset = 0; +function getApps(){ + const exit_app = { + name: 'Exit', + special: true + }; + const raw_apps = Storage.list(/\.info$/).filter(app => app.endsWith('.info')).map(app => Storage.readJSON(app,1) || { name: "DEAD: "+app.substr(1) }) + .filter(app=>app.type=="app" || app.type=="clock" || !app.type) + .sort((a,b)=>{ + var n=(0|a.sortorder)-(0|b.sortorder); + if (n) return n; // do sortorder first + if (a.name<b.name) return -1; + if (a.name>b.name) return 1; + return 0; + }).map(raw => ({ + name: raw.name, + src: raw.src, + icon: raw.icon, + version: raw.version + })); -const back = { - name: 'BACK', - back: true -}; - -let icons = {}; - -const apps = [back].concat(getApps()); -apps.push(back); - -function noIcon(x, y, size){ - const half = size/2; - g.setColor(1,1,1); - g.setFontAlign(-0,0); - const fontSize = Math.floor(size / 30 * 2); - g.setFont('6x8', fontSize); - if(fontSize) g.drawString('-?-', x+1.5, y); - g.drawRect(x-half, y-half, x+half, y+half); + const apps = [Object.assign({}, exit_app)].concat(raw_apps); + apps.push(exit_app); + return apps.map((app, i) => { + app.x = getPosition(i); + return app; + }); } -function drawIcons(offset){ - apps.forEach((app, i) => { - const x = getPosition(i) + HALF - offset; - const y = HALF - (HALF*0.3);//-(HALF*0.7); - let diff = (x - HALF); - if(diff < 0) diff *=-1; +const APPS = getApps(); - const dontRender = x+(HALF/2)<0 || x-(HALF/2)>120; - if(dontRender) { - delete icons[app.name]; +function noIcon(x, y, scale){ + if(scale < 0.2) return; + g.setColor(scale, scale, scale); + g.setFontAlign(0,0); + g.setFont('6x8',settings.highres ? 6:3); + g.drawString('x_x', x+1.5, y); + const h = (ORIGINAL_ICON_SIZE/3); + g.drawRect(x-h, y-h, x+h, y+h); +} + +function render(){ + const start = Date.now(); + + const ANIMATION_FRAME = settings.frame; + const ANIMATION_STEP = Math.floor(HALF / ANIMATION_FRAME); + const THRESHOLD = ANIMATION_STEP - 1; + + g.clear(); + const visibleApps = APPS.filter(app => app.x >= STATE.offset-HALF && app.x <= STATE.offset+WIDTH-HALF ); + + visibleApps.forEach(app => { + + const x = app.x+HALF-STATE.offset; + const y = HALF - (HALF*0.3); + + let dist = HALF - x; + if(dist < 0) dist *= -1; + + const scale = 1 - (dist / HALF); + + if(!scale) return; + + if(app.special){ + const font = settings.highres ? '6x8' : '4x6'; + const fontSize = settings.highres ? 2 : 1; + g.setFont(font, fontSize); + g.setColor(scale,scale,scale); + g.setFontAlign(0,0); + g.drawString(app.name, HALF, HALF); return; } - let size = 30; - if((diff*0.5) < size) size -= (diff*0.5); - else size = 0; - const scale = size / 30; - if(size){ - let c = size / 30 * 2; - c = c -1; - if(c < 0) c = 0; + //draw icon + const icon = app.icon ? + icons[app.name] ? icons[app.name] : Storage.read(app.icon) + : null; - if(app.back){ - g.setFont('6x8', 1); - g.setFontAlign(0, -1); - g.setColor(c,c,c); - g.drawString('Back', HALF, HALF); - return; + if(icon){ + icons[app.name] = icon; + try { + const rescale = settings.highres ? scale*ORIGINAL_ICON_SIZE : (scale*(ORIGINAL_ICON_SIZE/2)); + const imageScale = settings.highres ? scale*2 : scale; + g.drawImage(icon, x-rescale, y-rescale, { scale: imageScale }); + } catch(e){ + noIcon(x, y, scale); } - // icon + }else{ + noIcon(x, y, scale); + } - const icon = app.icon ? - icons[app.name] ? icons[app.name] : Storage.read(app.icon) - : null; - if(icon){ - icons[app.name] = icon; - try { - g.drawImage(icon, x-(scale*24), y-(scale*24), { scale: scale }); - } catch(e){ - noIcon(x, y, size); - } - }else{ - noIcon(x, y, size); - } - //text - g.setFont('6x8', 1); - g.setFontAlign(0, -1); - g.setColor(c,c,c); - g.drawString(app.name, HALF, HEIGHT - (HALF*0.7)); + //draw text + g.setColor(scale,scale,scale); + if(scale > 0.1){ + const font = settings.highres ? '6x8': '4x6'; + const fontSize = settings.highres ? 2 : 1; + g.setFont(font, fontSize); + g.setFontAlign(0,0); + g.drawString(app.name, HALF, HEIGHT/4*3); + } + if(settings.highres){ const type = app.type ? app.type : 'App'; const version = app.version ? app.version : '0.00'; const info = type+' v'+version; g.setFontAlign(0,1); - g.setFont('4x6', 0.25); - g.setColor(c,c,c); - g.drawString(info, HALF, 110, { scale: scale }); + g.setFont('6x8', 1.5); + g.setColor(scale,scale,scale); + g.drawString(info, HALF, 215, { scale: scale }); } - }); -} -function draw(ignoreLoop){ - g.setColor(0,0,0); - g.fillRect(0,0,WIDTH,HEIGHT); - drawIcons(slideOffset); + }); + + const duration = Math.floor(Date.now()-start); + if(settings.debug){ + g.setFontAlign(0,1); + g.setColor(0, 1, 0); + const fontSize = settings.highres ? 2 : 1; + g.setFont('4x6',fontSize); + g.drawString('Render: '+duration+'ms', HALF, HEIGHT); + } g.flip(); - if(slideOffset == target) return; - if(slideOffset < target) slideOffset+= ANIMATION_STEP; - else if(slideOffset > target) slideOffset -= ANIMATION_STEP; - if(!ignoreLoop) draw(); + if(STATE.offset == STATE.target) return; + + if(STATE.offset < STATE.target) STATE.offset += ANIMATION_STEP; + else if(STATE.offset > STATE.target) STATE.offset -= ANIMATION_STEP; + + if(STATE.offset >= STATE.target-THRESHOLD && STATE.offset < STATE.target) STATE.offset = STATE.target; + if(STATE.offset <= STATE.target+THRESHOLD && STATE.offset > STATE.target) STATE.offset = STATE.target; + setTimeout(render, 0); } function animateTo(index){ - target = getPosition(index); - draw(); -} -function goTo(index){ - current_app = index; - target = getPosition(index); - slideOffset = target; - draw(true); + STATE.index = index; + STATE.target = getPosition(index); + render(); } -goTo(1); +function jumpTo(index){ + STATE.index = index; + STATE.target = getPosition(index); + STATE.offset = STATE.target; + render(); +} function prev(){ - if(current_app == 0) goTo(apps.length-1); - current_app -= 1; - if(current_app < 0) current_app = 0; - animateTo(current_app); + if(STATE.settings_open) return; + if(STATE.index == 0) jumpTo(APPS.length-1); + setTimeout(() => { + if(!settings.animation) jumpTo(STATE.index-1); + else animateTo(STATE.index-1); + },1); } function next(){ - if(current_app == apps.length-1) goTo(0); - current_app += 1; - if(current_app > apps.length-1) current_app = apps.length-1; - animateTo(current_app); + if(STATE.settings_open) return; + if(STATE.index == APPS.length-1) jumpTo(0); + setTimeout(() => { + if(!settings.animation) jumpTo(STATE.index+1); + else animateTo(STATE.index+1); + },1); } -function run() { - const app = apps[current_app]; - if(app.back) return load(); +function run(){ + + const app = APPS[STATE.index]; + if(app.name == 'Exit') return load(); + if (Storage.read(app.src)===undefined) { E.showMessage("App Source\nNot found"); - setTimeout(draw, 2000); + setTimeout(render, 2000); } else { Bangle.setLCDMode(); g.clear(); @@ -162,15 +208,12 @@ function run() { E.showMessage("Loading..."); load(app.src); } + } - -setWatch(prev, BTN1, { repeat: true }); -setWatch(next, BTN3, { repeat: true }); -setWatch(run, BTN2, {repeat:true,edge:"falling"}); - // Screen event Bangle.on('touch', function(button){ + if(STATE.settings_open) return; switch(button){ case 1: prev(); @@ -185,6 +228,7 @@ Bangle.on('touch', function(button){ }); Bangle.on('swipe', dir => { + if(STATE.settings_open) return; if(dir == 1) prev(); else next(); }); @@ -193,3 +237,10 @@ Bangle.on('swipe', dir => { Bangle.on('lcdPower', on => { if(!on) return load(); }); + + +setWatch(prev, BTN1, { repeat: true }); +setWatch(next, BTN3, { repeat: true }); +setWatch(run, BTN2, { repeat:true }); + +jumpTo(1); \ No newline at end of file diff --git a/apps/toucher/settings.js b/apps/toucher/settings.js new file mode 100644 index 000000000..6f7320513 --- /dev/null +++ b/apps/toucher/settings.js @@ -0,0 +1,59 @@ +(function(back) { + + const Storage = require("Storage"); + const filename = 'toucher.json'; + let settings = Storage.readJSON(filename,1)|| null; + + function getSettings(){ + return { + highres: true, + animation : true, + frame : 3, + debug: true + }; + } + + function updateSettings() { + require("Storage").writeJSON(filename, settings); + Bangle.buzz(); + } + + if(!settings){ + settings = getSettings(); + updateSettings(); + } + + function saveChange(name){ + return function(v){ + settings[name] = v; + updateSettings(); + } + } + + E.showMenu({ + '': { 'title': 'Toucher settings' }, + "Resolution" : { + value : settings.highres, + format : v => v?"High":"Low", + onchange: v => { + saveChange('highres')(!settings.highres); + } + }, + "Animation" : { + value : settings.animation, + format : v => v?"On":"Off", + onchange : saveChange('animation') + }, + "Frame rate" : { + value : settings.frame, + min: 1, max: 10, step: 1, + onchange : saveChange('frame') + }, + "Debug" : { + value : settings.debug, + format : v => v?"On":"Off", + onchange : saveChange('debug') + }, + '< Back': back + }); +}); \ No newline at end of file diff --git a/apps/trex/ChangeLog b/apps/trex/ChangeLog new file mode 100644 index 000000000..42c1df403 --- /dev/null +++ b/apps/trex/ChangeLog @@ -0,0 +1 @@ +0.02: Add "ram" keyword to allow 2v06 Espruino builds to cache function that needs to be fast diff --git a/apps/trex/trex.js b/apps/trex/trex.js index 92c5d049c..fe84cb31a 100644 --- a/apps/trex/trex.js +++ b/apps/trex/trex.js @@ -165,6 +165,7 @@ function gameStop() { } function onFrame() { + "ram" g.clear(); if (rex.alive) { frame++; diff --git a/apps/verticalface/ChangeLog b/apps/verticalface/ChangeLog new file mode 100644 index 000000000..c30b02411 --- /dev/null +++ b/apps/verticalface/ChangeLog @@ -0,0 +1,2 @@ +0.04: Fixed day being displayed +0.05: Stop hours being displayed wrong if moving from 2 digits to 1 (fix #516) diff --git a/apps/verticalface/app-icon.js b/apps/verticalface/app-icon.js new file mode 100644 index 000000000..a3b7a6dec --- /dev/null +++ b/apps/verticalface/app-icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("MDAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADT4+Pj4+DQAAAAANPj4+Pj4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANDTg4ODg4DQ0ABg0xODg4ODgNDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+OAAAAAAAOD4ADT44AAAAAAA+OAAAAABWVjJWVlZWVlZWVjIAAAAAAAAAAAAAAAA+OAAAAAAAOD4ADT44AAAAAAA+OAAAAABWMgBWK1YrVlZWVisAAAAAAAAAAAAAAAA+OAAAAAAAOD4ADT44AAAAAAA+OAAAAAArVgBWKysAVgArAFYAAAAAAAAAAAAAAAANDQAAAAAAOD4ADT44AAAANzg+OAAAAABWVgAyK1ZWMgArVisAAAAAAAAAAAAAAAAAAAAAAAAAOD4ADT44AAAAOD4+OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOD4ADT44ADc4DQ0+OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOD4ADT44ADg+DQA+OAAAAACBgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg+DQAADT4+Pg0AAAA+OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABg0NDTg4DQAADT44OA0AAAA+OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADT4+Pg0AAAAADT44AAAAAAA+OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANMTg4OA0AAAAADT44AAAAAAA+OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+OAAAAAAAAAAADT44AAAAAAA+OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+ODg4ODg4ODgABw03ODg4ODgNDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+Pj4+Pj4+Pj4AAAANPj4+Pj4AAAAAAABWVlZWVlYrVgAAAAAAAAAAAAAAAAAAAAANDQ0NDQ0NDQ0AAAAHDQ0NDQ0AAAAAAABWVlZWVjIyVgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABWVlYAKysAVgAAAAAAAAAAAAAAAAAAAAAADT4+Pj4+DQAAAAAAADg+DQAAAAAAAABWVjIAKysAMgAAAAAAAAAAAAAAAAAAAAANDTg4ODg4DQ0AAAAHDTg+DQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+OAAAAAAAOD4AAAANPj4+DQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+OAAAAAAAOD4ABw03ODg+DQAAAAAAAACBgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+OAAAAAAAOD4ADT44ADg+DQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+OAAAAA04OD4ABw0NADg+DQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+OAAAADg+Pj4AAAAAADg+DQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+OAANODENOD4AAAAAADg+DQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+OAANPg0AOD4AAAAAADg+DQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+Pj44AAAAOD4AAAAAADg+DQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+ODg3AAAAOD4AAAAAADg+DQAAAAAAAABWVlYAVlZWVlZWVjJWVgAAAAAAAAAAAAA+OAAAAAAAOD4AAAAAADg+DQAAAAAAAABWAFZWVlZWVlZWKzJWMgAAAAAAAAAAAAA+OAAAAAAAOD4AAAAAADg+DQAAAAAAAABWK1YAVitWVjJWAFZWAAAAAAAAAAAAAAA+OAAAAAAAOD4AAAAAADg+DQAAAAAAAABWVjIAVisyMisrVitWVgAAAAAAAAAAAAANMTg4ODg4MQ0ABzg4ODg+ODgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADT4+Pj4+DQAADT4+Pj4+Pj4AAAAAAACBgV0yVgAAAAAAAAAAAAAAAAAAAAAAAAAABg0NDQ0NBgAABg0NDQ0NDQ0AAAAAAACBgTJdKwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBgVZWKwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABWVlZWVgAAAAAAAAAAAAAAAAAAAAAAAA0NBwAHBgcADQANBg0NAA0ADQcNDQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0NNw04DQ0ADQ0NDQ04AA0NNzg4OAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0NDQA4DQ0ADQ04DQ0HAA0NOA0NDQ0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYGBwAHDQcADQcNBwcAAA0ADQcHDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")) diff --git a/apps/verticalface/app.js b/apps/verticalface/app.js new file mode 100644 index 000000000..52c8e47a7 --- /dev/null +++ b/apps/verticalface/app.js @@ -0,0 +1,154 @@ +require("Font8x12").add(Graphics); +let HRMstate = false; +let currentHRM = "CALC"; + + +function drawTimeDate() { + var d = new Date(); + var h = d.getHours(), m = d.getMinutes(), day = d.getDate(), month = d.getMonth(), weekDay = d.getDay(); + + var daysOfWeek = ["SUN", "MON", "TUE","WED","THU","FRI","SAT"]; + var hours = (" "+h).substr(-2); + var mins= ("0"+m).substr(-2); + var date = `${daysOfWeek[weekDay]}|${day}|${("0"+(month+1)).substr(-2)}`; + + + // Reset the state of the graphics library + g.reset(); + // Set color + g.setColor('#2ecc71'); + // draw the current time (4x size 7 segment) + g.setFont("8x12",9); + g.setFontAlign(-1,0); // align right bottom + g.drawString(hours, 25, 65, true /*clear background*/); + g.drawString(mins, 25, 155, true /*clear background*/); + + // draw the date (2x size 7 segment) + g.setFont("6x8",2); + g.setFontAlign(-1,0); // align right bottom + g.drawString(date, 20, 215, true /*clear background*/); +} + + +//We will create custom "Widgets" for our face. + +function drawSteps() { + //Reset to defaults. + g.reset(); + // draw the date (2x size 7 segment) + g.setColor('#7f8c8d'); + g.setFont("8x12",2); + g.setFontAlign(-1,0); // align right bottom + g.drawString("STEPS", 145, 40, true /*clear background*/); + g.setColor('#bdc3c7'); + g.drawString("-", 145, 65, true /*clear background*/); +} + +function drawBPM(on) { + //Reset to defaults. + g.reset(); + g.setColor('#7f8c8d'); + g.setFont("8x12",2); + g.setFontAlign(-1,0); + var heartRate = 0; + + if(on){ + g.drawString("BPM", 145, 105, true); + g.setColor('#e74c3c'); + g.drawString("*", 190, 105, false); + g.setColor('#bdc3c7'); + //Showing current heartrate reading. + heartRate = currentHRM.toString() + " "; + return g.drawString(heartRate, 145, 130, true /*clear background*/); + } else { + g.drawString("BPM ", 145, 105, true /*clear background*/); + g.setColor('#bdc3c7'); + return g.drawString("- ", 145, 130, true); //Padding + } +} + +function drawBattery() { + let charge = E.getBattery(); + //Reset to defaults. + g.reset(); + // draw the date (2x size 7 segment) + g.setColor('#7f8c8d'); + g.setFont("8x12",2); + g.setFontAlign(-1,0); // align right bottom + g.drawString("CHARGE", 145, 170, true /*clear background*/); + g.setColor('#bdc3c7'); + g.drawString(`${charge}%`, 145, 195, true /*clear background*/); +} + + +// Clear the screen once, at startup +g.clear(); + +// draw immediately at first +drawTimeDate(); +drawSteps(); +drawBPM(); +drawBattery(); + +var secondInterval = setInterval(()=>{ + drawTimeDate(); +}, 15000); + +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + secondInterval = setInterval(()=>{ + drawTimeDate(); + }, 15000); + //Screen on + drawBPM(HRMstate); + drawTimeDate(); + drawBattery(); + } else { + //Screen off + clearInterval(secondInterval); + } +}); + +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); + +Bangle.on('touch', function(button) { + if(button == 1 || button == 2){ + Bangle.showLauncher(); + } +}); + +//HRM Controller. +setWatch(function(){ + if(!HRMstate){ + console.log("Toggled HRM"); + //Turn on. + Bangle.buzz(); + Bangle.setHRMPower(1); + currentHRM = "CALC"; + HRMstate = true; + } else if(HRMstate){ + console.log("Toggled HRM"); + //Turn off. + Bangle.buzz(); + Bangle.setHRMPower(0); + HRMstate = false; + currentHRM = []; + } + drawBPM(HRMstate); +}, BTN1, { repeat: true, edge: "falling" }); + +Bangle.on('HRM', function(hrm) { + if(hrm.confidence > 90){ + /*Do more research to determine effect algorithm for heartrate average.*/ + console.log(hrm.bpm); + currentHRM = hrm.bpm; + drawBPM(HRMstate); + } +}); + + +//Bangle.on('step', function(up) { +// console.log("Step"); +//}); diff --git a/apps/verticalface/app.png b/apps/verticalface/app.png new file mode 100644 index 000000000..f7e1cba57 Binary files /dev/null and b/apps/verticalface/app.png differ diff --git a/apps/viewstl/ChangeLog b/apps/viewstl/ChangeLog new file mode 100644 index 000000000..fa2dcb2e1 --- /dev/null +++ b/apps/viewstl/ChangeLog @@ -0,0 +1,2 @@ +0.01: New app! +0.02: Add accelerometer/compass viewing mode diff --git a/apps/viewstl/README.md b/apps/viewstl/README.md new file mode 100644 index 000000000..2676f3df7 --- /dev/null +++ b/apps/viewstl/README.md @@ -0,0 +1,24 @@ +# ViewSTL + +A simple viewer to render 3D models on-screen. The STL files have to be of the ASCII (non-binary) type. The rendering process can become quite slow +for models with more than ~200-300 facets. + +The app contains a number of inlined C routines and makes use of the microcontroller's FPU. Therefore, the app installed on the watch contains a base64 encoded binary +blob with those routines. The full C code is provided on github. + +## Controls + +The app supports 4 different rendering modes, swiping right-to-left on the touch screen cycles through them: +- shaded polygons +- shaded polygons with edge highlighting +- wireframe, only edges between non-coplanar facets visible +- wireframe, all facet (triangle) edges visible + +There are three different rotation modes that slightly alter the function of buttons 1 and 3, swiping left-to-right cycles through the modes: +- free rotation: button 1 zooms in, button 3 out +- Z-axis (vertical axis) rotation: buttons 1 and 3 tilt the Z-axis +- align rotation with compass and accelerometer readings: button 1 zooms in, button 3 out + +There is currently no interface to upload STL files to the watch, the web IDE storage icon can be used instead. + + diff --git a/apps/viewstl/cube.stl b/apps/viewstl/cube.stl new file mode 100644 index 000000000..4214221c9 --- /dev/null +++ b/apps/viewstl/cube.stl @@ -0,0 +1,86 @@ +solid OpenSCAD_Model + facet normal -0 0 1 + outer loop + vertex -5 5 5 + vertex 5 -5 5 + vertex 5 5 5 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex 5 -5 5 + vertex -5 5 5 + vertex -5 -5 5 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex -5 -5 -5 + vertex 5 5 -5 + vertex 5 -5 -5 + endloop + endfacet + facet normal -0 0 -1 + outer loop + vertex 5 5 -5 + vertex -5 -5 -5 + vertex -5 5 -5 + endloop + endfacet + facet normal 0 -1 0 + outer loop + vertex -5 -5 -5 + vertex 5 -5 5 + vertex -5 -5 5 + endloop + endfacet + facet normal 0 -1 -0 + outer loop + vertex 5 -5 5 + vertex -5 -5 -5 + vertex 5 -5 -5 + endloop + endfacet + facet normal 1 -0 0 + outer loop + vertex 5 -5 5 + vertex 5 5 -5 + vertex 5 5 5 + endloop + endfacet + facet normal 1 0 0 + outer loop + vertex 5 5 -5 + vertex 5 -5 5 + vertex 5 -5 -5 + endloop + endfacet + facet normal 0 1 -0 + outer loop + vertex 5 5 -5 + vertex -5 5 5 + vertex 5 5 5 + endloop + endfacet + facet normal 0 1 0 + outer loop + vertex -5 5 5 + vertex 5 5 -5 + vertex -5 5 -5 + endloop + endfacet + facet normal -1 0 0 + outer loop + vertex -5 -5 -5 + vertex -5 5 5 + vertex -5 5 -5 + endloop + endfacet + facet normal -1 -0 0 + outer loop + vertex -5 5 5 + vertex -5 -5 -5 + vertex -5 -5 5 + endloop + endfacet +endsolid OpenSCAD_Model diff --git a/apps/viewstl/fish_s.stl b/apps/viewstl/fish_s.stl new file mode 100644 index 000000000..70fd28b9a --- /dev/null +++ b/apps/viewstl/fish_s.stl @@ -0,0 +1,756 @@ +vertex 14.9126 -29.5887 -2.45 +vertex 14.9126 -30.3423 -2.45 +vertex 14.5569 -30.5817 -2.45 +vertex 6.72119 -16.5392 -2.45 +vertex -1.03592 -22.6875 -2.45 +vertex 6.04466 -15.0197 -2.45 +vertex 6.72119 -16.5392 -2.45 +vertex 7.95726 -17.6521 -2.45 +vertex 4.71675 -23.2921 -2.45 +vertex -6.32993 -13.4515 -2.45 +vertex 6.04466 -15.0197 -2.45 +vertex -6.39731 -15.1134 -2.45 +vertex -10.4974 -6.57382 -2.45 +vertex 11.945 -2.57918 -2.45 +vertex 8.9903 -9.35725 -2.45 +vertex 2.85788 12.68 -2.45 +vertex 12.0948 -2.03583 -2.45 +vertex 11.945 -2.57918 -2.45 +vertex 2.85788 22.58 -2.45 +vertex 8.548 23.2529 -2.45 +vertex 5.71576 17.63 -2.45 +vertex 11.945 15.8392 -2.45 +vertex 5.71576 17.63 -2.45 +vertex 8.9903 22.6172 -2.45 +vertex 8.54802 -9.99295 -2.45 +vertex 7.18376 -11.3057 -2.45 +vertex 8.9903 -9.35725 -2.45 +vertex 13.1679 6.37802 -2.45 +vertex 12.0948 -2.03583 -2.45 +vertex 2.85788 12.68 -2.45 +vertex 3.4908 27.6563 -2.45 +vertex 4.50931 27.1392 -2.45 +vertex 2.85788 22.58 -2.45 +vertex -0.965637 28.4369 -2.45 +vertex 3.4908 27.6563 -2.45 +vertex 2.85788 22.58 -2.45 +vertex -6.16991 25.9155 -2.45 +vertex -2.85788 22.58 -2.45 +vertex -6.87122 25.2755 -2.45 +vertex -6.16991 25.9155 -2.45 +vertex -1.60059 28.3899 -2.45 +vertex -2.85788 22.58 -2.45 +vertex -0.965637 28.4369 -2.45 +vertex -1.60059 28.3899 -2.45 +vertex -1.53212 28.4165 -2.45 +vertex -1.60059 28.3899 -2.45 +vertex -0.965637 28.4369 -2.45 +vertex -2.85788 22.58 -2.45 +vertex -5.71576 17.63 -2.45 +vertex -6.87122 25.2755 -2.45 +vertex -2.85788 22.58 -2.45 +vertex -10.7635 19.2449 -2.45 +vertex -10.4974 19.8338 -2.45 +vertex -5.71576 17.63 -2.45 +vertex -12.8441 11.4566 -2.45 +vertex -10.7635 19.2449 -2.45 +vertex -5.71576 17.63 -2.45 +vertex -12.9115 10.9427 -2.45 +vertex -12.8441 11.4566 -2.45 +vertex -2.85788 12.68 -2.45 +vertex 12.0948 15.2958 -2.45 +vertex 13.1679 6.88196 -2.45 +vertex 2.85788 12.68 -2.45 +vertex -12.8441 1.80342 -2.45 +vertex -12.9115 2.31732 -2.45 +vertex -2.85788 12.68 -2.45 +vertex -10.7635 -5.98489 -2.45 +vertex -12.8441 1.80342 -2.45 +vertex -2.85788 12.68 -2.45 +vertex 2.85788 12.68 -2.45 +vertex 13.1679 6.88196 -2.45 +vertex 13.1679 6.37802 -2.45 +vertex -2.85788 12.68 -2.45 +vertex 11.945 -2.57918 -2.45 +vertex -10.7635 -5.98489 -2.45 +vertex -2.85788 12.68 -2.45 +vertex 2.85788 12.68 -2.45 +vertex 11.945 -2.57918 -2.45 +vertex -10.4974 -6.57382 -2.45 +vertex -10.7635 -5.98489 -2.45 +vertex 11.945 -2.57918 -2.45 +vertex 7.18376 -11.3057 -2.45 +vertex -10.4974 -6.57382 -2.45 +vertex 8.9903 -9.35725 -2.45 +vertex 7.18376 -11.3057 -2.45 +vertex -6.94434 -11.9058 -2.45 +vertex -10.4974 -6.57382 -2.45 +vertex 7.18376 -11.3057 -2.45 +vertex 6.04466 -13.3564 -2.45 +vertex -6.94434 -11.9058 -2.45 +vertex -6.94434 -11.9058 -2.45 +vertex 6.04466 -13.3564 -2.45 +vertex -6.32993 -13.4515 -2.45 +vertex -6.32993 -13.4515 -2.45 +vertex 6.04466 -13.3564 -2.45 +vertex 6.04466 -15.0197 -2.45 +vertex -6.39731 -15.1134 -2.45 +vertex -1.03592 -22.6875 -2.45 +vertex -2.69011 -22.8613 -2.45 +vertex -7.59648 -17.0965 -2.45 +vertex -6.39731 -15.1134 -2.45 +vertex -2.69011 -22.8613 -2.45 +vertex -11.8228 -20.9019 -2.45 +vertex -7.59648 -17.0965 -2.45 +vertex -8.19138 -24.6488 -2.45 +vertex -12.3062 -21.5673 -2.45 +vertex -9.63184 -25.4805 -2.45 +vertex -14.5012 -26.4973 -2.45 +vertex -9.63184 -25.4805 -2.45 +vertex -14.3856 -29.7607 -2.45 +vertex -14.6722 -27.3018 -2.45 +vertex -14.6722 -27.3018 -2.45 +vertex -14.3856 -29.7607 -2.45 +vertex -14.6722 -29.7463 -2.45 +vertex -14.6722 -29.7463 -2.45 +vertex -14.3856 -29.7607 -2.45 +vertex -14.6312 -29.9392 -2.45 +vertex -14.5012 -26.4973 -2.45 +vertex -9.63184 -25.4805 -2.45 +vertex -14.6722 -27.3018 -2.45 +vertex 14.9126 -29.5887 -2.45 +vertex 14.5569 -30.5817 -2.45 +vertex 12.5441 -27.8112 -2.45 +vertex -12.3062 -21.5673 -2.45 +vertex -8.19138 -24.6488 -2.45 +vertex -9.63184 -25.4805 -2.45 +vertex -6.39731 -15.1134 -2.45 +vertex 6.04466 -15.0197 -2.45 +vertex -1.03592 -22.6875 -2.45 +vertex -12.3062 -21.5673 -2.45 +vertex -11.8228 -20.9019 -2.45 +vertex -8.19138 -24.6488 -2.45 +vertex -8.19138 -24.6488 -2.45 +vertex -7.59648 -17.0965 -2.45 +vertex -2.69011 -22.8613 -2.45 +vertex 6.72119 -16.5392 -2.45 +vertex 4.71675 -23.2921 -2.45 +vertex -1.03592 -22.6875 -2.45 +vertex 7.95726 -17.6521 -2.45 +vertex 9.67282 -18.6426 -2.45 +vertex 6.29861 -23.8061 -2.45 +vertex 7.95726 -17.6521 -2.45 +vertex 6.29861 -23.8061 -2.45 +vertex 4.71675 -23.2921 -2.45 +vertex 6.29861 -23.8061 -2.45 +vertex 10.2841 -19.193 -2.45 +vertex 13.456 -23.5588 -2.45 +vertex 9.67282 -18.6426 -2.45 +vertex 10.2841 -19.193 -2.45 +vertex 6.29861 -23.8061 -2.45 +vertex 6.29861 -23.8061 -2.45 +vertex 13.456 -23.5588 -2.45 +vertex 11.308 -26.6983 -2.45 +vertex 12.5441 -27.8112 -2.45 +vertex 11.308 -26.6983 -2.45 +vertex 13.7906 -24.3102 -2.45 +vertex 11.308 -26.6983 -2.45 +vertex 13.456 -23.5588 -2.45 +vertex 13.7906 -24.3102 -2.45 +vertex 14.9126 -29.5887 -2.45 +vertex 12.5441 -27.8112 -2.45 +vertex 13.7906 -24.3102 -2.45 +vertex 14.7 -30.7105 -2.45 +vertex 14.5569 -30.5817 -2.45 +vertex 14.9126 -30.3423 -2.45 +vertex 12.0948 15.2958 -2.45 +vertex 5.71576 17.63 -2.45 +vertex 11.945 15.8392 -2.45 +vertex -12.9115 2.31732 -2.45 +vertex -12.9115 10.9427 -2.45 +vertex -2.85788 12.68 -2.45 +vertex -2.85788 12.68 -2.45 +vertex -12.8441 11.4566 -2.45 +vertex -5.71576 17.63 -2.45 +vertex -5.71576 17.63 -2.45 +vertex -10.4974 19.8338 -2.45 +vertex -6.87122 25.2755 -2.45 +vertex -2.85788 22.58 -2.45 +vertex -0.965637 28.4369 -2.45 +vertex 2.85788 22.58 -2.45 +vertex 2.85788 22.58 -2.45 +vertex 4.50931 27.1392 -2.45 +vertex 8.548 23.2529 -2.45 +vertex 2.85788 12.68 -2.45 +vertex 5.71576 17.63 -2.45 +vertex 12.0948 15.2958 -2.45 +vertex 5.71576 17.63 -2.45 +vertex 8.548 23.2529 -2.45 +vertex 8.9903 22.6172 -2.45 +vertex 14.5569 -30.5817 2.45 +vertex 14.9126 -30.3423 2.45 +vertex 14.9126 -29.5887 2.45 +vertex 6.04466 -15.0197 2.45 +vertex -1.03592 -22.6875 2.45 +vertex 6.72119 -16.5392 2.45 +vertex 4.71675 -23.2921 2.45 +vertex 7.95726 -17.6521 2.45 +vertex 6.72119 -16.5392 2.45 +vertex -6.39731 -15.1134 2.45 +vertex 6.04466 -15.0197 2.45 +vertex -6.32993 -13.4515 2.45 +vertex 8.9903 -9.35725 2.45 +vertex 11.945 -2.57918 2.45 +vertex -10.4974 -6.57382 2.45 +vertex 11.945 -2.57918 2.45 +vertex 12.0948 -2.03583 2.45 +vertex 2.85788 12.68 2.45 +vertex 5.71576 17.63 2.45 +vertex 8.548 23.2529 2.45 +vertex 2.85788 22.58 2.45 +vertex 8.9903 22.6172 2.45 +vertex 5.71576 17.63 2.45 +vertex 11.945 15.8392 2.45 +vertex 8.9903 -9.35725 2.45 +vertex 7.18376 -11.3057 2.45 +vertex 8.54802 -9.99295 2.45 +vertex 2.85788 12.68 2.45 +vertex 12.0948 -2.03583 2.45 +vertex 13.1679 6.37802 2.45 +vertex 2.85788 22.58 2.45 +vertex 4.50931 27.1392 2.45 +vertex 3.4908 27.6563 2.45 +vertex 2.85788 22.58 2.45 +vertex 3.4908 27.6563 2.45 +vertex -0.965637 28.4369 2.45 +vertex -6.87122 25.2755 2.45 +vertex -2.85788 22.58 2.45 +vertex -6.16991 25.9155 2.45 +vertex -2.85788 22.58 2.45 +vertex -1.60059 28.3899 2.45 +vertex -6.16991 25.9155 2.45 +vertex -1.53212 28.4165 2.45 +vertex -1.60059 28.3899 2.45 +vertex -0.965637 28.4369 2.45 +vertex -2.85788 22.58 2.45 +vertex -0.965637 28.4369 2.45 +vertex -1.60059 28.3899 2.45 +vertex -2.85788 22.58 2.45 +vertex -6.87122 25.2755 2.45 +vertex -5.71576 17.63 2.45 +vertex -5.71576 17.63 2.45 +vertex -10.4974 19.8338 2.45 +vertex -10.7635 19.2449 2.45 +vertex -5.71576 17.63 2.45 +vertex -10.7635 19.2449 2.45 +vertex -12.8441 11.4566 2.45 +vertex -2.85788 12.68 2.45 +vertex -12.8441 11.4566 2.45 +vertex -12.9115 10.9427 2.45 +vertex 2.85788 12.68 2.45 +vertex 13.1679 6.88196 2.45 +vertex 12.0948 15.2958 2.45 +vertex -2.85788 12.68 2.45 +vertex -12.9115 2.31732 2.45 +vertex -12.8441 1.80342 2.45 +vertex -2.85788 12.68 2.45 +vertex -12.8441 1.80342 2.45 +vertex -10.7635 -5.98489 2.45 +vertex 13.1679 6.37802 2.45 +vertex 13.1679 6.88196 2.45 +vertex 2.85788 12.68 2.45 +vertex -10.7635 -5.98489 2.45 +vertex 11.945 -2.57918 2.45 +vertex -2.85788 12.68 2.45 +vertex 11.945 -2.57918 2.45 +vertex 2.85788 12.68 2.45 +vertex -2.85788 12.68 2.45 +vertex 11.945 -2.57918 2.45 +vertex -10.7635 -5.98489 2.45 +vertex -10.4974 -6.57382 2.45 +vertex 8.9903 -9.35725 2.45 +vertex -10.4974 -6.57382 2.45 +vertex 7.18376 -11.3057 2.45 +vertex -10.4974 -6.57382 2.45 +vertex -6.94434 -11.9058 2.45 +vertex 7.18376 -11.3057 2.45 +vertex -6.94434 -11.9058 2.45 +vertex 6.04466 -13.3564 2.45 +vertex 7.18376 -11.3057 2.45 +vertex -6.32993 -13.4515 2.45 +vertex 6.04466 -13.3564 2.45 +vertex -6.94434 -11.9058 2.45 +vertex 6.04466 -15.0197 2.45 +vertex 6.04466 -13.3564 2.45 +vertex -6.32993 -13.4515 2.45 +vertex -2.69011 -22.8613 2.45 +vertex -1.03592 -22.6875 2.45 +vertex -6.39731 -15.1134 2.45 +vertex -2.69011 -22.8613 2.45 +vertex -6.39731 -15.1134 2.45 +vertex -7.59648 -17.0965 2.45 +vertex -8.19138 -24.6488 2.45 +vertex -7.59648 -17.0965 2.45 +vertex -11.8228 -20.9019 2.45 +vertex -14.5012 -26.4973 2.45 +vertex -9.63184 -25.4805 2.45 +vertex -12.3062 -21.5673 2.45 +vertex -14.6722 -27.3018 2.45 +vertex -14.3856 -29.7607 2.45 +vertex -9.63184 -25.4805 2.45 +vertex -14.6722 -29.7463 2.45 +vertex -14.3856 -29.7607 2.45 +vertex -14.6722 -27.3018 2.45 +vertex -14.6312 -29.9392 2.45 +vertex -14.3856 -29.7607 2.45 +vertex -14.6722 -29.7463 2.45 +vertex -14.6722 -27.3018 2.45 +vertex -9.63184 -25.4805 2.45 +vertex -14.5012 -26.4973 2.45 +vertex 12.5441 -27.8112 2.45 +vertex 14.5569 -30.5817 2.45 +vertex 14.9126 -29.5887 2.45 +vertex -9.63184 -25.4805 2.45 +vertex -8.19138 -24.6488 2.45 +vertex -12.3062 -21.5673 2.45 +vertex -1.03592 -22.6875 2.45 +vertex 6.04466 -15.0197 2.45 +vertex -6.39731 -15.1134 2.45 +vertex -8.19138 -24.6488 2.45 +vertex -11.8228 -20.9019 2.45 +vertex -12.3062 -21.5673 2.45 +vertex -2.69011 -22.8613 2.45 +vertex -7.59648 -17.0965 2.45 +vertex -8.19138 -24.6488 2.45 +vertex -1.03592 -22.6875 2.45 +vertex 4.71675 -23.2921 2.45 +vertex 6.72119 -16.5392 2.45 +vertex 6.29861 -23.8061 2.45 +vertex 9.67282 -18.6426 2.45 +vertex 7.95726 -17.6521 2.45 +vertex 4.71675 -23.2921 2.45 +vertex 6.29861 -23.8061 2.45 +vertex 7.95726 -17.6521 2.45 +vertex 13.456 -23.5588 2.45 +vertex 10.2841 -19.193 2.45 +vertex 6.29861 -23.8061 2.45 +vertex 6.29861 -23.8061 2.45 +vertex 10.2841 -19.193 2.45 +vertex 9.67282 -18.6426 2.45 +vertex 11.308 -26.6983 2.45 +vertex 13.456 -23.5588 2.45 +vertex 6.29861 -23.8061 2.45 +vertex 13.7906 -24.3102 2.45 +vertex 11.308 -26.6983 2.45 +vertex 12.5441 -27.8112 2.45 +vertex 13.7906 -24.3102 2.45 +vertex 13.456 -23.5588 2.45 +vertex 11.308 -26.6983 2.45 +vertex 13.7906 -24.3102 2.45 +vertex 12.5441 -27.8112 2.45 +vertex 14.9126 -29.5887 2.45 +vertex 14.9126 -30.3423 2.45 +vertex 14.5569 -30.5817 2.45 +vertex 14.7 -30.7105 2.45 +vertex 11.945 15.8392 2.45 +vertex 5.71576 17.63 2.45 +vertex 12.0948 15.2958 2.45 +vertex -2.85788 12.68 2.45 +vertex -12.9115 10.9427 2.45 +vertex -12.9115 2.31732 2.45 +vertex -5.71576 17.63 2.45 +vertex -12.8441 11.4566 2.45 +vertex -2.85788 12.68 2.45 +vertex -6.87122 25.2755 2.45 +vertex -10.4974 19.8338 2.45 +vertex -5.71576 17.63 2.45 +vertex 2.85788 22.58 2.45 +vertex -0.965637 28.4369 2.45 +vertex -2.85788 22.58 2.45 +vertex 8.548 23.2529 2.45 +vertex 4.50931 27.1392 2.45 +vertex 2.85788 22.58 2.45 +vertex 12.0948 15.2958 2.45 +vertex 5.71576 17.63 2.45 +vertex 2.85788 12.68 2.45 +vertex 8.9903 22.6172 2.45 +vertex 8.548 23.2529 2.45 +vertex 5.71576 17.63 2.45 +vertex 14.9126 -29.5887 -2.45 +vertex 14.9126 -30.3423 2.45 +vertex 14.9126 -30.3423 -2.45 +vertex 14.9126 -29.5887 -2.45 +vertex 14.9126 -29.5887 2.45 +vertex 14.9126 -30.3423 2.45 +vertex 13.7906 -24.3102 -2.45 +vertex 14.9126 -29.5887 2.45 +vertex 14.9126 -29.5887 -2.45 +vertex 13.7906 -24.3102 -2.45 +vertex 13.7906 -24.3102 2.45 +vertex 14.9126 -29.5887 2.45 +vertex 13.456 -23.5588 -2.45 +vertex 13.7906 -24.3102 2.45 +vertex 13.7906 -24.3102 -2.45 +vertex 13.456 -23.5588 -2.45 +vertex 13.456 -23.5588 2.45 +vertex 13.7906 -24.3102 2.45 +vertex 10.2841 -19.193 -2.45 +vertex 13.456 -23.5588 2.45 +vertex 13.456 -23.5588 -2.45 +vertex 10.2841 -19.193 -2.45 +vertex 10.2841 -19.193 2.45 +vertex 13.456 -23.5588 2.45 +vertex 9.67282 -18.6426 -2.45 +vertex 10.2841 -19.193 2.45 +vertex 10.2841 -19.193 -2.45 +vertex 9.67282 -18.6426 -2.45 +vertex 9.67282 -18.6426 2.45 +vertex 10.2841 -19.193 2.45 +vertex 7.95726 -17.6521 -2.45 +vertex 9.67282 -18.6426 2.45 +vertex 9.67282 -18.6426 -2.45 +vertex 7.95726 -17.6521 -2.45 +vertex 7.95726 -17.6521 2.45 +vertex 9.67282 -18.6426 2.45 +vertex 6.72119 -16.5392 -2.45 +vertex 7.95726 -17.6521 2.45 +vertex 7.95726 -17.6521 -2.45 +vertex 6.72119 -16.5392 -2.45 +vertex 6.72119 -16.5392 2.45 +vertex 7.95726 -17.6521 2.45 +vertex 6.04466 -15.0197 -2.45 +vertex 6.72119 -16.5392 2.45 +vertex 6.72119 -16.5392 -2.45 +vertex 6.04466 -15.0197 -2.45 +vertex 6.04466 -15.0197 2.45 +vertex 6.72119 -16.5392 2.45 +vertex 6.04466 -13.3564 -2.45 +vertex 6.04466 -15.0197 2.45 +vertex 6.04466 -15.0197 -2.45 +vertex 6.04466 -13.3564 -2.45 +vertex 6.04466 -13.3564 2.45 +vertex 6.04466 -15.0197 2.45 +vertex 7.18376 -11.3057 -2.45 +vertex 6.04466 -13.3564 2.45 +vertex 6.04466 -13.3564 -2.45 +vertex 7.18376 -11.3057 -2.45 +vertex 7.18376 -11.3057 2.45 +vertex 6.04466 -13.3564 2.45 +vertex 8.54802 -9.99295 -2.45 +vertex 7.18376 -11.3057 2.45 +vertex 7.18376 -11.3057 -2.45 +vertex 8.54802 -9.99295 -2.45 +vertex 8.54802 -9.99295 2.45 +vertex 7.18376 -11.3057 2.45 +vertex 8.9903 -9.35725 -2.45 +vertex 8.54802 -9.99295 2.45 +vertex 8.54802 -9.99295 -2.45 +vertex 8.9903 -9.35725 -2.45 +vertex 8.9903 -9.35725 2.45 +vertex 8.54802 -9.99295 2.45 +vertex 11.945 -2.57918 -2.45 +vertex 8.9903 -9.35725 2.45 +vertex 8.9903 -9.35725 -2.45 +vertex 11.945 -2.57918 -2.45 +vertex 11.945 -2.57918 2.45 +vertex 8.9903 -9.35725 2.45 +vertex 12.0948 -2.03583 -2.45 +vertex 11.945 -2.57918 2.45 +vertex 11.945 -2.57918 -2.45 +vertex 12.0948 -2.03583 -2.45 +vertex 12.0948 -2.03583 2.45 +vertex 11.945 -2.57918 2.45 +vertex 13.1679 6.37802 -2.45 +vertex 12.0948 -2.03583 2.45 +vertex 12.0948 -2.03583 -2.45 +vertex 13.1679 6.37802 -2.45 +vertex 13.1679 6.37802 2.45 +vertex 12.0948 -2.03583 2.45 +vertex 13.1679 6.88196 -2.45 +vertex 13.1679 6.37802 2.45 +vertex 13.1679 6.37802 -2.45 +vertex 13.1679 6.88196 -2.45 +vertex 13.1679 6.88196 2.45 +vertex 13.1679 6.37802 2.45 +vertex 12.0948 15.2958 -2.45 +vertex 13.1679 6.88196 2.45 +vertex 13.1679 6.88196 -2.45 +vertex 12.0948 15.2958 -2.45 +vertex 12.0948 15.2958 2.45 +vertex 13.1679 6.88196 2.45 +vertex 11.945 15.8392 -2.45 +vertex 12.0948 15.2958 2.45 +vertex 12.0948 15.2958 -2.45 +vertex 11.945 15.8392 -2.45 +vertex 11.945 15.8392 2.45 +vertex 12.0948 15.2958 2.45 +vertex 8.9903 22.6172 -2.45 +vertex 11.945 15.8392 2.45 +vertex 11.945 15.8392 -2.45 +vertex 8.9903 22.6172 -2.45 +vertex 8.9903 22.6172 2.45 +vertex 11.945 15.8392 2.45 +vertex 8.548 23.2529 -2.45 +vertex 8.9903 22.6172 2.45 +vertex 8.9903 22.6172 -2.45 +vertex 8.548 23.2529 -2.45 +vertex 8.548 23.2529 2.45 +vertex 8.9903 22.6172 2.45 +vertex 4.50931 27.1392 -2.45 +vertex 8.548 23.2529 2.45 +vertex 8.548 23.2529 -2.45 +vertex 4.50931 27.1392 -2.45 +vertex 4.50931 27.1392 2.45 +vertex 8.548 23.2529 2.45 +vertex 3.4908 27.6563 -2.45 +vertex 4.50931 27.1392 2.45 +vertex 4.50931 27.1392 -2.45 +vertex 3.4908 27.6563 -2.45 +vertex 3.4908 27.6563 2.45 +vertex 4.50931 27.1392 2.45 +vertex -0.965637 28.4369 -2.45 +vertex 3.4908 27.6563 2.45 +vertex 3.4908 27.6563 -2.45 +vertex -0.965637 28.4369 -2.45 +vertex -0.965637 28.4369 2.45 +vertex 3.4908 27.6563 2.45 +vertex -1.53212 28.4165 -2.45 +vertex -0.965637 28.4369 2.45 +vertex -0.965637 28.4369 -2.45 +vertex -1.53212 28.4165 -2.45 +vertex -1.53212 28.4165 2.45 +vertex -0.965637 28.4369 2.45 +vertex -1.60059 28.3899 -2.45 +vertex -1.53212 28.4165 2.45 +vertex -1.53212 28.4165 -2.45 +vertex -1.60059 28.3899 -2.45 +vertex -1.60059 28.3899 2.45 +vertex -1.53212 28.4165 2.45 +vertex -6.16991 25.9155 -2.45 +vertex -1.60059 28.3899 2.45 +vertex -1.60059 28.3899 -2.45 +vertex -6.16991 25.9155 -2.45 +vertex -6.16991 25.9155 2.45 +vertex -1.60059 28.3899 2.45 +vertex -6.87122 25.2755 -2.45 +vertex -6.16991 25.9155 2.45 +vertex -6.16991 25.9155 -2.45 +vertex -6.87122 25.2755 -2.45 +vertex -6.87122 25.2755 2.45 +vertex -6.16991 25.9155 2.45 +vertex -10.4974 19.8338 -2.45 +vertex -6.87122 25.2755 2.45 +vertex -6.87122 25.2755 -2.45 +vertex -10.4974 19.8338 -2.45 +vertex -10.4974 19.8338 2.45 +vertex -6.87122 25.2755 2.45 +vertex -10.7635 19.2449 -2.45 +vertex -10.4974 19.8338 2.45 +vertex -10.4974 19.8338 -2.45 +vertex -10.7635 19.2449 -2.45 +vertex -10.7635 19.2449 2.45 +vertex -10.4974 19.8338 2.45 +vertex -12.8441 11.4566 -2.45 +vertex -10.7635 19.2449 2.45 +vertex -10.7635 19.2449 -2.45 +vertex -12.8441 11.4566 -2.45 +vertex -12.8441 11.4566 2.45 +vertex -10.7635 19.2449 2.45 +vertex -12.9115 10.9427 -2.45 +vertex -12.8441 11.4566 2.45 +vertex -12.8441 11.4566 -2.45 +vertex -12.9115 10.9427 -2.45 +vertex -12.9115 10.9427 2.45 +vertex -12.8441 11.4566 2.45 +vertex -12.9115 2.31732 -2.45 +vertex -12.9115 10.9427 2.45 +vertex -12.9115 10.9427 -2.45 +vertex -12.9115 2.31732 -2.45 +vertex -12.9115 2.31732 2.45 +vertex -12.9115 10.9427 2.45 +vertex -12.8441 1.80342 -2.45 +vertex -12.9115 2.31732 2.45 +vertex -12.9115 2.31732 -2.45 +vertex -12.8441 1.80342 -2.45 +vertex -12.8441 1.80342 2.45 +vertex -12.9115 2.31732 2.45 +vertex -10.7635 -5.98489 -2.45 +vertex -12.8441 1.80342 2.45 +vertex -12.8441 1.80342 -2.45 +vertex -10.7635 -5.98489 -2.45 +vertex -10.7635 -5.98489 2.45 +vertex -12.8441 1.80342 2.45 +vertex -10.4974 -6.57382 -2.45 +vertex -10.7635 -5.98489 2.45 +vertex -10.7635 -5.98489 -2.45 +vertex -10.4974 -6.57382 -2.45 +vertex -10.4974 -6.57382 2.45 +vertex -10.7635 -5.98489 2.45 +vertex -6.94434 -11.9058 -2.45 +vertex -10.4974 -6.57382 2.45 +vertex -10.4974 -6.57382 -2.45 +vertex -6.94434 -11.9058 -2.45 +vertex -6.94434 -11.9058 2.45 +vertex -10.4974 -6.57382 2.45 +vertex -6.32993 -13.4515 -2.45 +vertex -6.94434 -11.9058 2.45 +vertex -6.94434 -11.9058 -2.45 +vertex -6.32993 -13.4515 -2.45 +vertex -6.32993 -13.4515 2.45 +vertex -6.94434 -11.9058 2.45 +vertex -6.39731 -15.1134 -2.45 +vertex -6.32993 -13.4515 2.45 +vertex -6.32993 -13.4515 -2.45 +vertex -6.39731 -15.1134 -2.45 +vertex -6.39731 -15.1134 2.45 +vertex -6.32993 -13.4515 2.45 +vertex -7.59648 -17.0965 -2.45 +vertex -6.39731 -15.1134 2.45 +vertex -6.39731 -15.1134 -2.45 +vertex -7.59648 -17.0965 -2.45 +vertex -7.59648 -17.0965 2.45 +vertex -6.39731 -15.1134 2.45 +vertex -11.8228 -20.9019 -2.45 +vertex -7.59648 -17.0965 2.45 +vertex -7.59648 -17.0965 -2.45 +vertex -11.8228 -20.9019 -2.45 +vertex -11.8228 -20.9019 2.45 +vertex -7.59648 -17.0965 2.45 +vertex -12.3062 -21.5673 -2.45 +vertex -11.8228 -20.9019 2.45 +vertex -11.8228 -20.9019 -2.45 +vertex -12.3062 -21.5673 -2.45 +vertex -12.3062 -21.5673 2.45 +vertex -11.8228 -20.9019 2.45 +vertex -14.5012 -26.4973 -2.45 +vertex -12.3062 -21.5673 2.45 +vertex -12.3062 -21.5673 -2.45 +vertex -14.5012 -26.4973 -2.45 +vertex -14.5012 -26.4973 2.45 +vertex -12.3062 -21.5673 2.45 +vertex -14.6722 -27.3018 -2.45 +vertex -14.5012 -26.4973 2.45 +vertex -14.5012 -26.4973 -2.45 +vertex -14.6722 -27.3018 -2.45 +vertex -14.6722 -27.3018 2.45 +vertex -14.5012 -26.4973 2.45 +vertex -14.6722 -29.7463 -2.45 +vertex -14.6722 -27.3018 2.45 +vertex -14.6722 -27.3018 -2.45 +vertex -14.6722 -29.7463 -2.45 +vertex -14.6722 -29.7463 2.45 +vertex -14.6722 -27.3018 2.45 +vertex -14.6312 -29.9392 -2.45 +vertex -14.6722 -29.7463 2.45 +vertex -14.6722 -29.7463 -2.45 +vertex -14.6312 -29.9392 -2.45 +vertex -14.6312 -29.9392 2.45 +vertex -14.6722 -29.7463 2.45 +vertex -14.3856 -29.7607 -2.45 +vertex -14.6312 -29.9392 2.45 +vertex -14.6312 -29.9392 -2.45 +vertex -14.3856 -29.7607 -2.45 +vertex -14.3856 -29.7607 2.45 +vertex -14.6312 -29.9392 2.45 +vertex -9.63184 -25.4805 -2.45 +vertex -14.3856 -29.7607 2.45 +vertex -14.3856 -29.7607 -2.45 +vertex -9.63184 -25.4805 -2.45 +vertex -9.63184 -25.4805 2.45 +vertex -14.3856 -29.7607 2.45 +vertex -8.19138 -24.6488 -2.45 +vertex -9.63184 -25.4805 2.45 +vertex -9.63184 -25.4805 -2.45 +vertex -8.19138 -24.6488 -2.45 +vertex -8.19138 -24.6488 2.45 +vertex -9.63184 -25.4805 2.45 +vertex -2.69011 -22.8613 -2.45 +vertex -8.19138 -24.6488 2.45 +vertex -8.19138 -24.6488 -2.45 +vertex -2.69011 -22.8613 -2.45 +vertex -2.69011 -22.8613 2.45 +vertex -8.19138 -24.6488 2.45 +vertex -1.03592 -22.6875 -2.45 +vertex -2.69011 -22.8613 2.45 +vertex -2.69011 -22.8613 -2.45 +vertex -1.03592 -22.6875 -2.45 +vertex -1.03592 -22.6875 2.45 +vertex -2.69011 -22.8613 2.45 +vertex 4.71675 -23.2921 -2.45 +vertex -1.03592 -22.6875 2.45 +vertex -1.03592 -22.6875 -2.45 +vertex 4.71675 -23.2921 -2.45 +vertex 4.71675 -23.2921 2.45 +vertex -1.03592 -22.6875 2.45 +vertex 6.29861 -23.8061 -2.45 +vertex 4.71675 -23.2921 2.45 +vertex 4.71675 -23.2921 -2.45 +vertex 6.29861 -23.8061 -2.45 +vertex 6.29861 -23.8061 2.45 +vertex 4.71675 -23.2921 2.45 +vertex 11.308 -26.6983 -2.45 +vertex 6.29861 -23.8061 2.45 +vertex 6.29861 -23.8061 -2.45 +vertex 11.308 -26.6983 -2.45 +vertex 11.308 -26.6983 2.45 +vertex 6.29861 -23.8061 2.45 +vertex 12.5441 -27.8112 -2.45 +vertex 11.308 -26.6983 2.45 +vertex 11.308 -26.6983 -2.45 +vertex 12.5441 -27.8112 -2.45 +vertex 12.5441 -27.8112 2.45 +vertex 11.308 -26.6983 2.45 +vertex 14.5569 -30.5817 -2.45 +vertex 12.5441 -27.8112 2.45 +vertex 12.5441 -27.8112 -2.45 +vertex 14.5569 -30.5817 -2.45 +vertex 14.5569 -30.5817 2.45 +vertex 12.5441 -27.8112 2.45 +vertex 14.7 -30.7105 -2.45 +vertex 14.5569 -30.5817 2.45 +vertex 14.5569 -30.5817 -2.45 +vertex 14.7 -30.7105 -2.45 +vertex 14.7 -30.7105 2.45 +vertex 14.5569 -30.5817 2.45 +vertex 14.9126 -30.3423 -2.45 +vertex 14.7 -30.7105 2.45 +vertex 14.7 -30.7105 -2.45 +vertex 14.9126 -30.3423 -2.45 +vertex 14.9126 -30.3423 2.45 +vertex 14.7 -30.7105 2.45 +vertex -5.71576 17.63 -2.45 +vertex -5.71576 17.63 2.45 +vertex -2.85788 12.68 -2.45 +vertex -2.85788 12.68 2.45 +vertex -2.85788 12.68 -2.45 +vertex -5.71576 17.63 2.45 +vertex -2.85788 22.58 -2.45 +vertex -2.85788 22.58 2.45 +vertex -5.71576 17.63 -2.45 +vertex -5.71576 17.63 2.45 +vertex -5.71576 17.63 -2.45 +vertex -2.85788 22.58 2.45 +vertex 2.85788 22.58 -2.45 +vertex 2.85788 22.58 2.45 +vertex -2.85788 22.58 -2.45 +vertex -2.85788 22.58 2.45 +vertex -2.85788 22.58 -2.45 +vertex 2.85788 22.58 2.45 +vertex 5.71576 17.63 -2.45 +vertex 5.71576 17.63 2.45 +vertex 2.85788 22.58 -2.45 +vertex 2.85788 22.58 2.45 +vertex 2.85788 22.58 -2.45 +vertex 5.71576 17.63 2.45 +vertex 2.85788 12.68 -2.45 +vertex 2.85788 12.68 2.45 +vertex 5.71576 17.63 -2.45 +vertex 5.71576 17.63 2.45 +vertex 5.71576 17.63 -2.45 +vertex 2.85788 12.68 2.45 +vertex -2.85788 12.68 -2.45 +vertex -2.85788 12.68 2.45 +vertex 2.85788 12.68 -2.45 +vertex 2.85788 12.68 2.45 +vertex 2.85788 12.68 -2.45 +vertex -2.85788 12.68 2.45 diff --git a/apps/viewstl/icons8-octahedron-48.png b/apps/viewstl/icons8-octahedron-48.png new file mode 100644 index 000000000..1cc129763 Binary files /dev/null and b/apps/viewstl/icons8-octahedron-48.png differ diff --git a/apps/viewstl/icosa.stl b/apps/viewstl/icosa.stl new file mode 100644 index 000000000..7c783fe7b --- /dev/null +++ b/apps/viewstl/icosa.stl @@ -0,0 +1,142 @@ +solid OpenSCAD_Model + facet normal 0 -0.356822 0.934172 + outer loop + vertex 0.5 0 0.809017 + vertex -0.5 0 0.809017 + vertex 0 -0.809017 0.5 + endloop + endfacet + facet normal 0.57735 -0.57735 0.57735 + outer loop + vertex 0.5 0 0.809017 + vertex 0 -0.809017 0.5 + vertex 0.809017 -0.5 0 + endloop + endfacet + facet normal 0.934172 0 0.356822 + outer loop + vertex 0.5 0 0.809017 + vertex 0.809017 -0.5 0 + vertex 0.809017 0.5 0 + endloop + endfacet + facet normal 0.57735 0.57735 0.57735 + outer loop + vertex 0.5 0 0.809017 + vertex 0.809017 0.5 0 + vertex 0 0.809017 0.5 + endloop + endfacet + facet normal 0 0.356822 0.934172 + outer loop + vertex 0.5 0 0.809017 + vertex 0 0.809017 0.5 + vertex -0.5 0 0.809017 + endloop + endfacet + facet normal 0 -0.356822 -0.934172 + outer loop + vertex -0.5 0 -0.809017 + vertex 0.5 0 -0.809017 + vertex 0 -0.809017 -0.5 + endloop + endfacet + facet normal -0.57735 -0.57735 -0.57735 + outer loop + vertex -0.5 0 -0.809017 + vertex 0 -0.809017 -0.5 + vertex -0.809017 -0.5 0 + endloop + endfacet + facet normal -0.934172 0 -0.356822 + outer loop + vertex -0.5 0 -0.809017 + vertex -0.809017 -0.5 0 + vertex -0.809017 0.5 0 + endloop + endfacet + facet normal -0.57735 0.57735 -0.57735 + outer loop + vertex -0.5 0 -0.809017 + vertex -0.809017 0.5 0 + vertex 0 0.809017 -0.5 + endloop + endfacet + facet normal 0 0.356822 -0.934172 + outer loop + vertex -0.5 0 -0.809017 + vertex 0 0.809017 -0.5 + vertex 0.5 0 -0.809017 + endloop + endfacet + facet normal -0.934172 0 0.356822 + outer loop + vertex -0.5 0 0.809017 + vertex -0.809017 0.5 0 + vertex -0.809017 -0.5 0 + endloop + endfacet + facet normal -0.57735 -0.57735 0.57735 + outer loop + vertex -0.5 0 0.809017 + vertex -0.809017 -0.5 0 + vertex 0 -0.809017 0.5 + endloop + endfacet + facet normal -0.356822 -0.934172 -0 + outer loop + vertex 0 -0.809017 0.5 + vertex -0.809017 -0.5 0 + vertex 0 -0.809017 -0.5 + endloop + endfacet + facet normal 0.356822 -0.934172 0 + outer loop + vertex 0 -0.809017 0.5 + vertex 0 -0.809017 -0.5 + vertex 0.809017 -0.5 0 + endloop + endfacet + facet normal 0.57735 -0.57735 -0.57735 + outer loop + vertex 0.809017 -0.5 0 + vertex 0 -0.809017 -0.5 + vertex 0.5 0 -0.809017 + endloop + endfacet + facet normal 0.934172 0 -0.356822 + outer loop + vertex 0.809017 -0.5 0 + vertex 0.5 0 -0.809017 + vertex 0.809017 0.5 0 + endloop + endfacet + facet normal 0.57735 0.57735 -0.57735 + outer loop + vertex 0.809017 0.5 0 + vertex 0.5 0 -0.809017 + vertex 0 0.809017 -0.5 + endloop + endfacet + facet normal 0.356822 0.934172 0 + outer loop + vertex 0.809017 0.5 0 + vertex 0 0.809017 -0.5 + vertex 0 0.809017 0.5 + endloop + endfacet + facet normal -0.356822 0.934172 0 + outer loop + vertex 0 0.809017 0.5 + vertex 0 0.809017 -0.5 + vertex -0.809017 0.5 0 + endloop + endfacet + facet normal -0.57735 0.57735 0.57735 + outer loop + vertex 0 0.809017 0.5 + vertex -0.809017 0.5 0 + vertex -0.5 0 0.809017 + endloop + endfacet +endsolid OpenSCAD_Model diff --git a/apps/viewstl/tetra.stl b/apps/viewstl/tetra.stl new file mode 100644 index 000000000..ca5cc351e --- /dev/null +++ b/apps/viewstl/tetra.stl @@ -0,0 +1,30 @@ +solid OpenSCAD_Model + facet normal 0 -0 -1 + outer loop + vertex 0 5.7735 -2.04124 + vertex 5 -2.88675 -2.04124 + vertex -5 -2.88675 -2.04124 + endloop + endfacet + facet normal -0.816496 0.471405 0.333334 + outer loop + vertex 0 0 6.12372 + vertex 0 5.7735 -2.04124 + vertex -5 -2.88675 -2.04124 + endloop + endfacet + facet normal 0.816496 0.471405 0.333334 + outer loop + vertex 0 5.7735 -2.04124 + vertex 0 0 6.12372 + vertex 5 -2.88675 -2.04124 + endloop + endfacet + facet normal 0 -0.942809 0.333333 + outer loop + vertex 0 0 6.12372 + vertex -5 -2.88675 -2.04124 + vertex 5 -2.88675 -2.04124 + endloop + endfacet +endsolid OpenSCAD_Model diff --git a/apps/viewstl/toilet_s.stl b/apps/viewstl/toilet_s.stl new file mode 100644 index 000000000..78e4dc4f6 --- /dev/null +++ b/apps/viewstl/toilet_s.stl @@ -0,0 +1,516 @@ + vertex 19.7498 20 20 + vertex -32 20 72 + vertex -22.2161 20 20 + vertex -32 20 -50 + vertex -13.6629 20 -15 + vertex -18.2693 20 2.5 + vertex -32 20 -50 + vertex -18.2693 20 2.5 + vertex -22.2161 20 20 + vertex -32 20 -50 + vertex -22.2161 20 20 + vertex -32 20 72 + vertex -13.6629 20 -15 + vertex -32 20 -50 + vertex -12.5096 20 -32.5 + vertex -12.5096 20 -32.5 + vertex -32 20 -50 + vertex -13.3296 20 -50 + vertex -32 20 72 + vertex 19.7498 20 20 + vertex 32 20 72 + vertex 32 20 -50 + vertex 19.7498 20 20 + vertex 16.2412 20 2.5 + vertex 32 20 -50 + vertex 12.1461 20 -15 + vertex 11.1209 20 -32.5 + vertex 12.1461 20 -15 + vertex 32 20 -50 + vertex 16.2412 20 2.5 + vertex 32 20 -50 + vertex 11.1209 20 -32.5 + vertex 11.8499 20 -50 + vertex 19.7498 20 20 + vertex 32 20 -50 + vertex 32 20 72 + vertex -13.3296 20 -50 + vertex -21.1652 7.10585 -32.5 + vertex -12.5096 20 -32.5 + vertex 18.3851 15.2836 -50 + vertex 17.254 15.5738 -32.5 + vertex 22.5235 -2.52352 -32.5 + vertex 24 -4 -50 + vertex 22.5235 -2.52352 -32.5 + vertex 22.5235 -2.52353 -32.5 + vertex 22.5235 -2.52352 -32.5 + vertex 24 -4 -50 + vertex 18.3851 15.2836 -50 + vertex -22.5526 -14.2606 -50 + vertex 24 -4 -50 + vertex 18.3851 -23.2836 -50 + vertex 11.8499 20 -50 + vertex 24 -4 -50 + vertex -22.5526 6.2606 -50 + vertex -12 -29.9808 -50 + vertex 18.3851 -23.2836 -50 + vertex 4.16755 -33.5442 -50 + vertex 11.8499 20 -50 + vertex 32 45 -50 + vertex 32 20 -50 + vertex 18.3851 -23.2836 -50 + vertex -12 -29.9808 -50 + vertex -22.5526 -14.2606 -50 + vertex 24 -4 -50 + vertex -22.5526 -14.2606 -50 + vertex -22.5526 6.2606 -50 + vertex -32 45 -50 + vertex 11.8499 20 -50 + vertex -13.3296 20 -50 + vertex -32 45 -50 + vertex -13.3296 20 -50 + vertex -32 20 -50 + vertex 11.8499 20 -50 + vertex -32 45 -50 + vertex 32 45 -50 + vertex 24 -4 -50 + vertex 11.8499 20 -50 + vertex 18.3851 15.2836 -50 + vertex 11.8499 20 -50 + vertex -22.5526 6.2606 -50 + vertex -13.3296 20 -50 + vertex 24 -4 -50 + vertex 22.5235 -2.52353 -32.5 + vertex 18.3851 -23.2836 -50 + vertex 18.3851 -23.2836 -50 + vertex 17.254 -20.6208 -32.5 + vertex 3.91117 -30.2502 -32.5 + vertex 17.254 15.5738 -32.5 + vertex 18.3851 15.2836 -50 + vertex 11.8499 20 -50 + vertex 11.8499 20 -50 + vertex 11.1209 20 -32.5 + vertex 17.254 15.5738 -32.5 + vertex 3.91117 -30.2502 -32.5 + vertex -11.2618 -26.906 -32.5 + vertex 4.16755 -33.5442 -50 + vertex -11.2618 -26.906 -32.5 + vertex -12 -29.9808 -50 + vertex 4.16755 -33.5442 -50 + vertex -21.1652 -12.1529 -32.5 + vertex -22.5526 -14.2606 -50 + vertex -11.2618 -26.906 -32.5 + vertex -22.5526 6.2606 -50 + vertex -21.1652 -12.1529 -32.5 + vertex -21.1652 7.10584 -32.5 + vertex -21.1652 -12.1529 -32.5 + vertex -22.5526 6.2606 -50 + vertex -22.5526 -14.2606 -50 + vertex -22.5526 6.2606 -50 + vertex -21.1652 7.10585 -32.5 + vertex -13.3296 20 -50 + vertex -21.1652 7.10585 -32.5 + vertex -22.5526 6.2606 -50 + vertex -21.1652 7.10584 -32.5 + vertex 22.5235 -2.52353 -32.5 + vertex 17.254 -20.6208 -32.5 + vertex 18.3851 -23.2836 -50 + vertex 3.91117 -30.2502 -32.5 + vertex 4.16755 -33.5442 -50 + vertex 18.3851 -23.2836 -50 + vertex -12 -29.9808 -50 + vertex -11.2618 -26.906 -32.5 + vertex -22.5526 -14.2606 -50 + vertex 24.6 -4.6 -15 + vertex 22.5235 -2.52352 -32.5 + vertex 18.8447 15.1657 -15 + vertex 22.5235 -2.52352 -32.5 + vertex 24.6 -4.6 -15 + vertex 22.5235 -2.52353 -32.5 + vertex 18.8447 15.1657 -15 + vertex 17.254 15.5738 -32.5 + vertex 12.1461 20 -15 + vertex 17.254 15.5738 -32.5 + vertex 11.1209 20 -32.5 + vertex 12.1461 20 -15 + vertex 4.27174 -34.8828 -15 + vertex -11.2618 -26.906 -32.5 + vertex 3.91117 -30.2502 -32.5 + vertex -21.1652 7.10585 -32.5 + vertex -13.6629 20 -15 + vertex -12.5096 20 -32.5 + vertex 18.8447 15.1657 -15 + vertex 22.5235 -2.52352 -32.5 + vertex 17.254 15.5738 -32.5 + vertex 22.5235 -2.52353 -32.5 + vertex 24.6 -4.6 -15 + vertex 18.8447 -24.3657 -15 + vertex -21.1652 -12.1529 -32.5 + vertex -11.2618 -26.906 -32.5 + vertex -23.1164 -15.1171 -15 + vertex 4.27174 -34.8828 -15 + vertex 3.91117 -30.2502 -32.5 + vertex 17.254 -20.6208 -32.5 + vertex 17.254 -20.6208 -32.5 + vertex 18.8447 -24.3657 -15 + vertex 4.27174 -34.8828 -15 + vertex 22.5235 -2.52353 -32.5 + vertex 18.8447 -24.3657 -15 + vertex 17.254 -20.6208 -32.5 + vertex -21.1652 -12.1529 -32.5 + vertex -23.1164 5.91711 -15 + vertex -21.1652 7.10584 -32.5 + vertex -23.1164 5.91711 -15 + vertex -21.1652 -12.1529 -32.5 + vertex -23.1164 -15.1171 -15 + vertex -12.3 -31.2303 -15 + vertex -11.2618 -26.906 -32.5 + vertex 4.27174 -34.8828 -15 + vertex -23.1164 5.91711 -15 + vertex -21.1652 7.10585 -32.5 + vertex -21.1652 7.10584 -32.5 + vertex -21.1652 7.10585 -32.5 + vertex -23.1164 5.91711 -15 + vertex -13.6629 20 -15 + vertex -11.2618 -26.906 -32.5 + vertex -12.3 -31.2303 -15 + vertex -23.1164 -15.1171 -15 + vertex 32.8939 -12.8939 2.5 + vertex 24.6 -4.6 -15 + vertex 25.1982 13.5358 2.5 + vertex 18.8447 15.1657 -15 + vertex 12.1461 20 -15 + vertex 16.2412 20 2.5 + vertex 18.8447 15.1657 -15 + vertex 16.2412 20 2.5 + vertex 25.1982 13.5358 2.5 + vertex 24.6 -4.6 -15 + vertex 18.8447 15.1657 -15 + vertex 25.1982 13.5358 2.5 + vertex 25.1982 -39.3236 2.5 + vertex 24.6 -4.6 -15 + vertex 32.8939 -12.8939 2.5 + vertex -13.6629 20 -15 + vertex -23.1164 5.91711 -15 + vertex -18.2693 20 2.5 + vertex -16.4469 -48.5026 2.5 + vertex -23.1164 -15.1171 -15 + vertex -12.3 -31.2303 -15 + vertex -23.1164 -15.1171 -15 + vertex -30.9101 1.16907 2.5 + vertex -23.1164 5.91711 -15 + vertex -30.9101 1.16907 2.5 + vertex -23.1164 -15.1171 -15 + vertex -30.9101 -26.9569 2.5 + vertex 5.71196 -53.3866 2.5 + vertex -16.4469 -48.5026 2.5 + vertex 4.27174 -34.8828 -15 + vertex 25.1982 -39.3236 2.5 + vertex 18.8447 -24.3657 -15 + vertex 24.6 -4.6 -15 + vertex 4.27174 -34.8828 -15 + vertex -16.4469 -48.5026 2.5 + vertex -12.3 -31.2303 -15 + vertex 5.71196 -53.3866 2.5 + vertex 4.27174 -34.8828 -15 + vertex 18.8447 -24.3657 -15 + vertex -23.1164 5.91711 -15 + vertex -30.9101 1.16907 2.5 + vertex -18.2693 20 2.5 + vertex 25.1982 -39.3236 2.5 + vertex 5.71196 -53.3866 2.5 + vertex 18.8447 -24.3657 -15 + vertex -16.4469 -48.5026 2.5 + vertex -30.9101 -26.9569 2.5 + vertex -23.1164 -15.1171 -15 + vertex 21.4492 2.49756 20 + vertex 40 -20 20 + vertex 30.6418 12.1394 20 + vertex 40 -20 20 + vertex 21.4492 2.49756 20 + vertex 28 -20 20 + vertex 19.7498 20 20 + vertex 21.4492 2.49756 20 + vertex 30.6418 12.1394 20 + vertex 19.7498 20 20 + vertex 4.86216 14.4683 20 + vertex 21.4492 2.49756 20 + vertex 19.7498 20 20 + vertex 4.86215 14.4683 20 + vertex 4.86216 14.4683 20 + vertex -22.2161 20 20 + vertex 4.86215 14.4683 20 + vertex 19.7498 20 20 + vertex 4.86215 14.4683 20 + vertex -22.2161 20 20 + vertex 4.86214 14.4683 20 + vertex 4.86214 14.4683 20 + vertex -22.2161 20 20 + vertex -14 10.3109 20 + vertex -37.5877 -2.899 20 + vertex -14 10.3109 20 + vertex -22.2161 20 20 + vertex -14 10.3109 20 + vertex -37.5877 -2.899 20 + vertex -26.3114 -8.02929 20 + vertex -26.3114 -8.0293 20 + vertex -37.5877 -2.899 20 + vertex -26.3114 -31.9707 20 + vertex -26.3114 -8.02929 20 + vertex -37.5877 -2.899 20 + vertex -26.3114 -8.0293 20 + vertex 21.4492 -42.4976 20 + vertex 40 -20 20 + vertex 28 -20 20 + vertex 40 -20 20 + vertex 21.4492 -42.4976 20 + vertex 30.6418 -52.1394 20 + vertex 4.86216 -54.4683 20 + vertex 30.6418 -52.1394 20 + vertex 21.4492 -42.4976 20 + vertex 30.6418 -52.1394 20 + vertex 4.86216 -54.4683 20 + vertex 6.94592 -69.2404 20 + vertex 4.86215 -54.4683 20 + vertex 6.94592 -69.2404 20 + vertex 4.86216 -54.4683 20 + vertex 4.86214 -54.4683 20 + vertex 6.94592 -69.2404 20 + vertex 4.86215 -54.4683 20 + vertex -20 -63.3013 20 + vertex 4.86214 -54.4683 20 + vertex -14 -50.3109 20 + vertex 4.86214 -54.4683 20 + vertex -20 -63.3013 20 + vertex 6.94592 -69.2404 20 + vertex -37.5877 -37.101 20 + vertex -14 -50.3109 20 + vertex -26.3114 -31.9707 20 + vertex -37.5877 -37.101 20 + vertex -26.3114 -31.9707 20 + vertex -37.5877 -2.899 20 + vertex -14 -50.3109 20 + vertex -37.5877 -37.101 20 + vertex -20 -63.3013 20 + vertex 32.8939 -12.8939 2.5 + vertex 30.6418 12.1394 20 + vertex 40 -20 20 + vertex 25.1982 13.5358 2.5 + vertex 16.2412 20 2.5 + vertex 19.7498 20 20 + vertex 25.1982 13.5358 2.5 + vertex 19.7498 20 20 + vertex 30.6418 12.1394 20 + vertex 32.8939 -12.8939 2.5 + vertex 25.1982 13.5358 2.5 + vertex 30.6418 12.1394 20 + vertex 40 -20 20 + vertex 30.6418 -52.1394 20 + vertex 32.8939 -12.8939 2.5 + vertex -20 -63.3013 20 + vertex -30.9101 -26.9569 2.5 + vertex -16.4469 -48.5026 2.5 + vertex -30.9101 -26.9569 2.5 + vertex -37.5877 -2.899 20 + vertex -30.9101 1.16907 2.5 + vertex -37.5877 -2.899 20 + vertex -30.9101 -26.9569 2.5 + vertex -37.5877 -37.101 20 + vertex 30.6418 -52.1394 20 + vertex 25.1982 -39.3236 2.5 + vertex 32.8939 -12.8939 2.5 + vertex 5.71196 -53.3866 2.5 + vertex -20 -63.3013 20 + vertex -16.4469 -48.5026 2.5 + vertex 6.94592 -69.2404 20 + vertex -20 -63.3013 20 + vertex 5.71196 -53.3866 2.5 + vertex -18.2693 20 2.5 + vertex -37.5877 -2.899 20 + vertex -22.2161 20 20 + vertex -30.9101 1.16907 2.5 + vertex -37.5877 -2.899 20 + vertex -18.2693 20 2.5 + vertex 6.94592 -69.2404 20 + vertex 5.71196 -53.3866 2.5 + vertex 30.6418 -52.1394 20 + vertex 30.6418 -52.1394 20 + vertex 5.71196 -53.3866 2.5 + vertex 25.1982 -39.3236 2.5 + vertex -20 -63.3013 20 + vertex -37.5877 -37.101 20 + vertex -30.9101 -26.9569 2.5 + vertex 17.3528 -38.2009 6.83361 + vertex 8.65248 -20 -1.30367 + vertex 6.62818 -26.9521 -1.30367 + vertex 4.86214 14.4683 20 + vertex -14 10.3109 20 + vertex 4.86215 14.4683 20 + vertex -26.3114 -8.0293 20 + vertex -26.3114 -31.9707 20 + vertex -26.3114 -8.02929 20 + vertex 28 -20 20 + vertex 21.4492 2.49757 20 + vertex 17.3528 -1.79909 6.83361 + vertex 22.6525 -20 6.83361 + vertex 28 -20 20 + vertex 17.3528 -1.79909 6.83361 + vertex 22.6525 -20 6.83361 + vertex 17.3528 -1.79909 6.83361 + vertex 8.65248 -20 -1.30367 + vertex 17.3528 -1.79909 6.83361 + vertex 21.4492 2.49757 20 + vertex 4.86215 14.4683 20 + vertex 4.86216 -54.4683 20 + vertex 21.4492 -42.4976 20 + vertex 4.86215 -54.4683 20 + vertex -8.13067 -16.3008 -1.30367 + vertex -11.3262 4.52203 6.83361 + vertex -21.2864 -10.3155 6.83361 + vertex 3.93356 7.88542 6.83361 + vertex 4.86215 14.4683 20 + vertex -11.3262 4.52203 6.83361 + vertex -14 -50.3109 20 + vertex 4.86214 -54.4683 20 + vertex 4.86215 -54.4683 20 + vertex 4.86215 -54.4683 20 + vertex 17.3528 -38.2009 6.83361 + vertex 3.93356 -47.8854 6.83361 + vertex -14 -50.3109 20 + vertex -21.2864 -29.6845 6.83361 + vertex -26.3114 -31.9707 20 + vertex 4.86215 -54.4683 20 + vertex -11.3262 -44.522 6.83361 + vertex -14 -50.3109 20 + vertex 21.4492 2.49757 20 + vertex 4.86216 14.4683 20 + vertex 4.86215 14.4683 20 + vertex 4.86216 14.4683 20 + vertex 21.4492 2.49757 20 + vertex 21.4492 2.49756 20 + vertex 21.4492 2.49757 20 + vertex 28 -20 20 + vertex 21.4492 2.49756 20 + vertex -21.2864 -10.3155 6.83361 + vertex -8.13067 -23.6992 -1.30367 + vertex -8.13067 -16.3008 -1.30367 + vertex -8.13067 -23.6992 -1.30367 + vertex -21.2864 -10.3155 6.83361 + vertex -21.2864 -29.6845 6.83361 + vertex 17.3528 -1.79909 6.83361 + vertex 4.86215 14.4683 20 + vertex 3.93356 7.88542 6.83361 + vertex 1.50249 -9.34872 -1.30367 + vertex 3.93356 7.88542 6.83361 + vertex -11.3262 4.52203 6.83361 + vertex -11.3262 4.52203 6.83361 + vertex 4.86215 14.4683 20 + vertex -14 10.3109 20 + vertex 28 -20 20 + vertex 22.6525 -20 6.83361 + vertex 17.3528 -38.2009 6.83361 + vertex 17.3528 -38.2009 6.83361 + vertex 22.6525 -20 6.83361 + vertex 8.65248 -20 -1.30367 + vertex -14 -50.3109 20 + vertex -11.3262 -44.522 6.83361 + vertex -21.2864 -29.6845 6.83361 + vertex 3.93356 -47.8854 6.83361 + vertex 17.3528 -38.2009 6.83361 + vertex 1.50249 -30.6513 -1.30367 + vertex -11.3262 4.52203 6.83361 + vertex -14 10.3109 20 + vertex -26.3114 -8.02929 20 + vertex 21.4492 -42.4976 20 + vertex 17.3528 -38.2009 6.83361 + vertex 4.86215 -54.4683 20 + vertex 21.4492 -42.4976 20 + vertex 28 -20 20 + vertex 17.3528 -38.2009 6.83361 + vertex -21.2864 -10.3155 6.83361 + vertex -11.3262 4.52203 6.83361 + vertex -26.3114 -8.02929 20 + vertex -26.3114 -8.02929 20 + vertex -21.2864 -29.6845 6.83361 + vertex -21.2864 -10.3155 6.83361 + vertex -21.2864 -29.6845 6.83361 + vertex -26.3114 -8.02929 20 + vertex -26.3114 -31.9707 20 + vertex 3.93356 -47.8854 6.83361 + vertex 1.50249 -30.6513 -1.30367 + vertex -11.3262 -44.522 6.83361 + vertex 4.86215 -54.4683 20 + vertex 3.93356 -47.8854 6.83361 + vertex -11.3262 -44.522 6.83361 + vertex 17.3528 -38.2009 6.83361 + vertex 6.62818 -26.9521 -1.30367 + vertex 1.50249 -30.6513 -1.30367 + vertex -4.32624 -10.6334 -1.30367 + vertex 1.50249 -9.34872 -1.30367 + vertex -11.3262 4.52203 6.83361 + vertex 1.50249 -30.6513 -1.30367 + vertex -4.32624 -29.3666 -1.30367 + vertex -11.3262 -44.522 6.83361 + vertex -11.3262 -44.522 6.83361 + vertex -8.13067 -23.6992 -1.30367 + vertex -21.2864 -29.6845 6.83361 + vertex 17.3528 -1.79909 6.83361 + vertex 3.93356 7.88542 6.83361 + vertex 1.50249 -9.34872 -1.30367 + vertex -4.32624 -29.3666 -1.30367 + vertex -8.13067 -23.6992 -1.30367 + vertex -11.3262 -44.522 6.83361 + vertex -8.13067 -16.3008 -1.30367 + vertex 8.65248 -20 -1.30367 + vertex 6.62818 -13.0479 -1.30367 + vertex -4.32624 -10.6334 -1.30367 + vertex 6.62818 -13.0479 -1.30367 + vertex 1.50249 -9.34872 -1.30367 + vertex -8.13067 -23.6992 -1.30367 + vertex 8.65248 -20 -1.30367 + vertex -8.13067 -16.3008 -1.30367 + vertex 6.62818 -13.0479 -1.30367 + vertex -4.32624 -10.6334 -1.30367 + vertex -8.13067 -16.3008 -1.30367 + vertex 8.65248 -20 -1.30367 + vertex -8.13067 -23.6992 -1.30367 + vertex 6.62818 -26.9521 -1.30367 + vertex -4.32624 -29.3666 -1.30367 + vertex 6.62818 -26.9521 -1.30367 + vertex -8.13067 -23.6992 -1.30367 + vertex 6.62818 -26.9521 -1.30367 + vertex -4.32624 -29.3666 -1.30367 + vertex 1.50249 -30.6513 -1.30367 + vertex -8.13067 -16.3008 -1.30367 + vertex -4.32624 -10.6334 -1.30367 + vertex -11.3262 4.52203 6.83361 + vertex 6.62818 -13.0479 -1.30367 + vertex 17.3528 -1.79909 6.83361 + vertex 1.50249 -9.34872 -1.30367 + vertex 8.65248 -20 -1.30367 + vertex 17.3528 -1.79909 6.83361 + vertex 6.62818 -13.0479 -1.30367 + vertex 32 20 72 + vertex 32 45 -50 + vertex 32 45 72 + vertex 32 45 -50 + vertex 32 20 72 + vertex 32 20 -50 + vertex -32 20 -50 + vertex -32 45 72 + vertex -32 45 -50 + vertex -32 45 72 + vertex -32 20 -50 + vertex -32 20 72 + vertex 32 45 -50 + vertex -32 45 72 + vertex 32 45 72 + vertex -32 45 72 + vertex 32 45 -50 + vertex -32 45 -50 + vertex -32 45 72 + vertex 32 20 72 + vertex 32 45 72 + vertex 32 20 72 + vertex -32 45 72 + vertex -32 20 72 diff --git a/apps/viewstl/viewstl-icon.js b/apps/viewstl/viewstl-icon.js new file mode 100644 index 000000000..afa7c1538 --- /dev/null +++ b/apps/viewstl/viewstl-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AA07iAutF4IwrFwM7mgwqFwU7nQvBGE4uDSAYwmFwovEGEYuGF4owhFw4vGGD4uIF44wdFxM7mgwiFxU7nQvHGDInExOz2eJSBgwYEoll6/X1vX2YvNGCqGFxPXLoIyBF5wwTWwxfB1oyBL54wSFwwrBAAWtBQk0GDYuGr6KCMILvFF5owNFwyNDYIgADnQvNGBYuHAAOzR4dlBYovOGBU6nQwIxOt1ouGF7QABiE0GRIAHFhkPeJwSCGR4tLhMPFxowEGQQvLmguIhIuRGAwyLnQtIFyYwIAAKXGF4otCFyowKGQy4EFzIwMfoYtFFzIwNRQoucGBwuhGBgujGBYukGBQulGBAunGA4uoGAsPF1IwEF1YwDF1n+mkQF1gA/AH4A/ADI")) diff --git a/apps/viewstl/viewstl.app.js b/apps/viewstl/viewstl.app.js new file mode 100644 index 000000000..0b2512176 --- /dev/null +++ b/apps/viewstl/viewstl.app.js @@ -0,0 +1,417 @@ +// globals +var u = [0, 1, 0]; // axis of rotation +var aux = new Float32Array(12); +var p_aux = E.getAddressOf(aux, true); +var a = 0.5; // angle of rotation +var light = new Float32Array(12); +var p_light = E.getAddressOf(light, true); +light[0] = 1/Math.sqrt(2); +light[1] = 1/Math.sqrt(2); +light[2] = 0; +var filex = new Float32Array(6); +var p_filex = E.getAddressOf(filex, true); +var addr = new Int32Array(12); +var p_addr = E.getAddressOf(addr, true); +var polyp = new Int32Array(6); +var p_polyp = E.getAddressOf(polyp, true); +var polyedge = new Int32Array(8); +var p_polyedge = E.getAddressOf(polyedge, true); +var edges; +var p_edges; +var zbuf; +var p_zbuf; +var zDist; +var points; +var p_points; +var rpoints; +var p_rpoints; +var npoints = 0; +var faces; +var p_faces; +var vpoints; +var p_vpoints; +var normals; +var p_normals; +var rnormals; +var p_rnormals; +var lastTime; +var nFrames = 0; +var interv; +var qZrot = 0; +var qWireframe = 0; +var zBeta = 0; + +const c05 = Math.cos(0.05); +const s05 = Math.sin(0.05); + +var c = E.compiledC(` +// void rotatePoints(int, int, int, int) +// void projectPoints(int, int, int, int) +// void popZBuf(int, int, int, int) +// int processFace(int, int, int) +// void initEdges(int, int) +// int findSlot(int, int, int) +void rotatePoints(float *p, float *res, int len, float *u) { + float c = u[3]; + float s = u[4]; + for (int i=0; i<len; ++i) { + res[3*i ] = p[3*i]*(c+u[0]*u[0]*(1-c)) + p[3*i+1]*(u[0]*u[1]*(1-c)-u[2]*s) + p[3*i+2]*(u[0]*u[2]*(1-c)+u[1]*s); + res[3*i+1] = p[3*i]*(u[1]*u[0]*(1-c)+u[2]*s) + p[3*i+1]*(c+u[1]*u[1]*(1-c)) + p[3*i+2]*(u[1]*u[2]*(1-c)-u[0]*s); + res[3*i+2] = p[3*i]*(u[2]*u[0]*(1-c)-u[1]*s) + p[3*i+1]*(u[2]*u[1]*(1-c)+u[0]*s) + p[3*i+2]*(c+u[2]*u[2]*(1-c)); + } +} +void projectPoints(float *p, short *res, int len, int zd) { + float zdist = zd/100.0; + for (int i=0; i<len; ++i) { + float dz = p[3*i+2]-zdist; + res[2*i+0] = (short)(120.0+320.0*p[3*i+0]/dz); + res[2*i+1] = (short)(80.0+320.0*p[3*i+1]/dz); + } +} +void quick_sort(int *base, unsigned int nel) +{ + int *pivot; + int tmp; + unsigned int left, right; + if (nel < 2) return; + pivot = base; + left = 0; + right = nel-1; + while (left < right) { + while (*(base+left)>*pivot && left<right) left++; + while (*(base+right)<*pivot && left<right) right--; + if (left<right && *(base+left)!=*(base+right)) { + if (base+left==pivot) { + pivot = base+right; + } else if (base+right==pivot) { + pivot = base+left; + } + tmp = *(base+left); *(base+left) = *(base+right); *(base+right) = tmp; + } else { + left++; + } + } + quick_sort(base, left-1); + quick_sort(base+left, nel-left); +} +void popZBuf(float *p, unsigned short *f, int *zb, int len) { + for (int i=0; i<len; ++i) { + int z = int(1000.0*(p[f[i*3]*3+2]+p[f[i*3+1]*3+2]+p[f[i*3+2]*3+2])); + zb[i] = (z<<10) | i; + } + quick_sort(zb, len); +} +int processFace(int *p, int z, int qWire) { + short *faces = (short *)p[0]; + float *rnormals = (float *)p[1]; + short *vpoints = (short *)p[2]; + int *polyp = (int *)p[3]; + float *light = (float *)p[4]; + char *edges = (char *)p[5]; + int *polyedge = (int *)p[6]; + int shade; + z = z & 0x3ff; + if (rnormals[z*3+2]>0) { + for (int j=0; j<3; ++j) { + polyp[j*2+0] = vpoints[faces[z*3+j]*2]; + polyp[j*2+1] = vpoints[faces[z*3+j]*2+1]; + } + if (qWire) { + char e = edges[z]; + switch(e) { + case 1: + polyedge[0]=polyp[0];polyedge[1]=polyp[1]; + polyedge[2]=polyp[2];polyedge[3]=polyp[3]; + polyedge[4]=polyp[0];polyedge[5]=polyp[1]; + polyedge[6]=polyp[2];polyedge[7]=polyp[3]; + break; + case 2: + polyedge[0]=polyp[2];polyedge[1]=polyp[3]; + polyedge[2]=polyp[4];polyedge[3]=polyp[5]; + polyedge[4]=polyp[2];polyedge[5]=polyp[3]; + polyedge[6]=polyp[4];polyedge[7]=polyp[5]; + break; + case 4: + polyedge[0]=polyp[4];polyedge[1]=polyp[5]; + polyedge[2]=polyp[0];polyedge[3]=polyp[1]; + polyedge[4]=polyp[4];polyedge[5]=polyp[5]; + polyedge[6]=polyp[0];polyedge[7]=polyp[1]; + break; + case 7: + for (int k=0; k<6; ++k) polyedge[k] = polyp[k]; + polyedge[6] = polyp[0]; polyedge[7] = polyp[1]; + break; + case 3: + for (int k=0; k<6; ++k) polyedge[k] = polyp[k]; + polyedge[6]=polyp[4]; polyedge[7]=polyp[5]; + break; + case 5: + polyedge[0]=polyp[4];polyedge[1]=polyp[5]; + polyedge[2]=polyp[0];polyedge[3]=polyp[1]; + polyedge[4]=polyp[2];polyedge[5]=polyp[3]; + polyedge[6]=polyp[2];polyedge[7]=polyp[3]; + break; + case 6: + polyedge[0]=polyp[2];polyedge[1]=polyp[3]; + polyedge[2]=polyp[4];polyedge[3]=polyp[5]; + polyedge[4]=polyp[0];polyedge[5]=polyp[1]; + polyedge[6]=polyp[0];polyedge[7]=polyp[1]; + break; + default: + for (int k=0; k<8; ++k) polyedge[k]=-1; + } + } + float s = 0.2+(1.0+rnormals[3*z+0]*light[0]+rnormals[3*z+1]*light[1]+rnormals[3*z+2]*light[2])/2.9; + shade = int(s*31) | (int(s*63)<<5) | (int(s*31)<<11); + return shade; + } + else return 0; +} +void initEdges(int *p, int len) { + short *faces = (short *)p[0]; + char *edges = (char *)p[5]; + float *normals = (float *)p[7]; + for (int i=0; i<len; ++i) { + char r=0; + for (int j=0; j<3; ++j) { + short e1=faces[j+i*3]; + short e2=faces[((j+1) % 3)+i*3]; + int k = len; + while (k--) { + if (i!=k && ((faces[k*3+1]==e1 && faces[k*3]==e2) || (faces[k*3+2]==e1 && faces[k*3+1]==e2) || (faces[k*3]==e1 && faces[k*3+2]==e2))) { + if (normals[k*3]*normals[i*3]+normals[k*3+1]*normals[i*3+1]+normals[k*3+2]*normals[i*3+2] < 0.95) r |= (1<<j); + k=0; + } + } + } + edges[i] = r; + } +} +int findSlot(float *p, float *x, int len) { + for (int i=0; i<len; ++i) + if (p[3*i]-x[0]<0.0001 && p[3*i]-x[0]>-0.0001 && p[3*i+1]-x[1]<0.0001 && p[3*i+1]-x[1]>-0.0001 && p[3*i+2]-x[2]<0.0001 && p[3*i+2]-x[2]>-0.0001) return i; + p[3*len] = x[0]; + p[3*len+1] = x[1]; + p[3*len+2] = x[2]; + return len; +} +`); + +function initNormals() { + var i = faces.length/3; + while (i--) { + normals[i*3+0] = (points[faces[3*i+1]*3+1]-points[faces[3*i+0]*3+1])*(points[faces[3*i+2]*3+2]-points[faces[3*i+0]*3+2]) - (points[faces[3*i+1]*3+2]-points[faces[3*i+0]*3+2])*(points[faces[3*i+2]*3+1]-points[faces[3*i+0]*3+1]); + normals[i*3+1] = (points[faces[3*i+1]*3+2]-points[faces[3*i+0]*3+2])*(points[faces[3*i+2]*3+0]-points[faces[3*i+0]*3+0]) - (points[faces[3*i+1]*3+0]-points[faces[3*i+0]*3+0])*(points[faces[3*i+2]*3+2]-points[faces[3*i+0]*3+2]); + normals[i*3+2] = (points[faces[3*i+1]*3+0]-points[faces[3*i+0]*3+0])*(points[faces[3*i+2]*3+1]-points[faces[3*i+0]*3+1]) - (points[faces[3*i+1]*3+1]-points[faces[3*i+0]*3+1])*(points[faces[3*i+2]*3+0]-points[faces[3*i+0]*3+0]); + var n = Math.sqrt(normals[i*3]*normals[i*3]+normals[i*3+1]*normals[i*3+1]+normals[i*3+2]*normals[i*3+2]); + if (n>0) { + normals[i*3] /= -n; + normals[i*3+1] /= -n; + normals[i*3+2] /= -n; + } + } +} + +function readSTL(fn) { + var fb = require("Storage").read(fn); + var nverts=0,i=0; while((i=fb.indexOf("vertex",i)+1)!=0) nverts++; + points = new Float32Array(nverts); + p_points = E.getAddressOf(points, true); + faces = new Uint16Array(nverts); + p_faces = E.getAddressOf(faces, true); + edges = new Uint8Array(Math.max(faces.length/3,24)) + p_edges = E.getAddressOf(edges, true); + var fp=0, p=0; + var nf = 0; + g.setColor(0.9, 0.9, 0.9); + g.drawRect(20, 140, 220, 160); + g.setColor(0.6, 0.6, 0.9); + while (p<fb.length) { + var line = ''; + while (fb[p]!="\n") line += fb[p++]; + p++; + if (line.toLowerCase().includes("vertex")) { + var v = line.trim().split(/\s+/); + filex[0] = v[1]; + filex[1] = v[3]; + filex[2] = v[2]; + var slot = 0|c.findSlot(p_points, p_filex, npoints); + if (slot==npoints) npoints++; + faces[fp++] = slot; + if (fp%3 == 0) g.fillRect(21, 141, 21+198*fp/nverts, 159); + } + } + vpoints = new Uint16Array(Math.max(12,2*npoints)); + p_vpoints = E.getAddressOf(vpoints, true); + normals = new Float32Array(faces.length); + p_normals = E.getAddressOf(normals, true); + initNormals(); + rnormals = new Float32Array(faces.length); + p_rnormals = E.getAddressOf(rnormals, true); + rpoints = new Float32Array(points.length); + p_rpoints = E.getAddressOf(rpoints, true); + zbuf = new Int32Array(Math.max(12,faces.length/3)); + p_zbuf = E.getAddressOf(zbuf, true); + addr[0] = p_faces; + addr[1] = p_rnormals; + addr[2] = p_vpoints; + addr[3] = p_polyp; + addr[4] = p_light; + addr[5] = p_edges; + addr[6] = p_polyedge; + addr[7] = p_normals; + c.initEdges(p_addr, faces.length/3); +} + +function rotV(v, u, c, s) { + "ram" + return [v[0]*(c+u[0]*u[0]*(1-c)) + v[1]*(u[0]*u[1]*(1-c)-u[2]*s) + v[2]*(u[0]*u[2]*(1-c)+u[1]*s), + v[0]*(u[1]*u[0]*(1-c)+u[2]*s) + v[1]*(c+u[1]*u[1]*(1-c)) + v[2]*(u[1]*u[2]*(1-c)-u[0]*s), + v[0]*(u[2]*u[0]*(1-c)-u[1]*s) + v[1]*(u[2]*u[1]*(1-c)+u[0]*s) + v[2]*(c+u[2]*u[2]*(1-c))]; +} + +function largestExtent(pts) { + var x = 0; + var i = pts.length/3; + while (i--) { + var e = pts[3*i]*pts[3*i]+pts[3*i+1]*pts[3*i+1]+pts[3*i+2]*pts[3*i+2]; + if (e>x) x = e; + } + return Math.sqrt(x); +} + +function draw() { + "ram" + const n = [1, 0, 0]; + if (qZrot>0) { + var ca, sa, cb, sb; + if (qZrot==2) { + var acc = Bangle.getAccel(); + zBeta = -Math.atan2(acc.z, -acc.y); + var comp = Bangle.getCompass(); + if (!isNaN(comp.heading)) { + var m = [comp.dx, comp.dy, comp.dz]; + //console.log(m); + var rm = rotV(m, [1, 0, 0], Math.cos(zBeta), Math.sin(zBeta)); + a = -Math.atan2(rm[0], rm[2]); + //console.log("heading="+a*180/Math.PI, "zBeta="+zBeta); + } + else a = 0; + } + ca=Math.cos(a); sa=Math.sin(a); cb=Math.cos(zBeta); sb=Math.sin(zBeta); + var ul = Math.sqrt(sb*sb+ca*ca*sb*sb+2*sa*sa*cb+2*ca*sb*sb+2*sa*sa); + u = [(sb+ca*sb)/ul, (-sa-sa*cb)/ul, (-sa*sb)/ul]; + var ra = Math.acos((ca+cb+ca*cb-1)/2); + if (ra<0) ra += Math.PI; + aux[3] = Math.cos(ra); + aux[4] = Math.sin(ra); + } + else{ + u = rotV(u, n, c05, s05); + aux[3] = Math.cos(a); + aux[4] = Math.sin(a); + } + a += 0.08; + aux[0] = u[0]; aux[1]=u[1]; aux[2]=u[2]; + c.rotatePoints(p_points, p_rpoints, npoints, p_aux); + c.rotatePoints(p_normals, p_rnormals, faces.length/3, p_aux); + c.projectPoints(p_rpoints, p_vpoints, npoints, 0|zDist*100); + c.popZBuf(p_rpoints, p_faces, p_zbuf, faces.length/3); + g.clear(); + var z, shade; + if (qWireframe>0) { + var i = faces.length/3; + while (i--) { + z = zbuf[i]; + shade = 0|c.processFace(p_addr, z, 1); + if (shade > 0) { + if (qWireframe==1) g.setColor(shade).fillPoly(polyp).setColor(0).drawPoly(polyedge); + else { + g.setColor(0).fillPoly(polyp).setColor(shade); + if (qWireframe==2) g.drawPoly(polyedge); + else g.drawPoly(polyp, true); + } + } + } + } + else { + var i = faces.length/3; + while (i--) { + z = zbuf[i]; + shade = 0|c.processFace(p_addr, z, 0); + if (shade > 0) g.setColor(shade).fillPoly(polyp); + } + } + nFrames++; + var fps = Math.round(nFrames*100000/(Date.now()-lastTime))/100; + g.setColor(0.7, 0.7, 0.7); + g.setFont("6x8", 1); + g.drawString("fps:"+fps.toString(), 20, 0); + g.flip(); +} + +function loadFile(fn) { + Bangle.setLCDMode("direct"); + g.clear(); + E.showMenu(); + E.showMessage("Loading...", fn); + readSTL(fn); + zDist = 5*largestExtent(points); + g.clear(); + g.setColor(1, 1, 1); + g.setFont("6x8", 2); + g.setFontAlign(-1, -1); + g.setColor(1, 0.5, 0.5); + g.drawString("Model info",15, 40); + g.setColor(1, 1, 1); + g.drawString("# faces: "+faces.length/3, 15, 80); + g.drawString("# vertices: "+npoints, 15, 110); + g.drawString("max extent: "+Math.round(100*(zDist/5))/100, 15, 140); + g.flip(); + setWatch(function() { + if (interv) { + interv = clearInterval(interv); + load(); + } + else { + Bangle.setLCDMode("doublebuffered"); + lastTime = Date.now(); + nFrames = 0; + interv = setInterval(function() { draw();}, 30); + } }, BTN2, {repeat:true, debounce:50}); + setWatch(function() { + if (qZrot==1) { + if (zBeta<2*Math.PI/2-0.08) zBeta += 0.08; + } else zDist *= 0.9; + }, BTN1, {repeat:true}); + setWatch(function() { + if (qZrot==1) { + if (zBeta>-2*Math.PI/2-0.08) zBeta -= 0.08; + } else zDist /= 0.9; + }, BTN3, {repeat:true}); + Bangle.on('swipe', function(direction){ + switch(direction){ + case 1: + qZrot = (qZrot+1)%3; + break; + case -1: + qWireframe = (qWireframe+1)%4; + break; + }}); +} + +function drawMenu() { + const menu = { + '': { 'title': 'STL files' } + }; + var files = require("Storage").list(".stl"); + for (var i=0; i<files.length; ++i) { + menu[files[i]] = loadFile.bind(null, files[i]); + } + menu['Exit'] = function() { load(); }; + E.showMenu(menu); +} + +Bangle.on('kill',()=>{Bangle.setCompassPower(0);}); +Bangle.setCompassPower(1); +drawMenu(); diff --git a/apps/viewstl/viewstl.min.js b/apps/viewstl/viewstl.min.js new file mode 100644 index 000000000..77469042c --- /dev/null +++ b/apps/viewstl/viewstl.min.js @@ -0,0 +1,279 @@ +// globals +var u = [0, 1, 0]; // axis of rotation +var aux = new Float32Array(12); +var p_aux = E.getAddressOf(aux, true); +var a = 0.5; // angle of rotation +var light = new Float32Array(12); +var p_light = E.getAddressOf(light, true); +light[0] = 1/Math.sqrt(2); +light[1] = 1/Math.sqrt(2); +light[2] = 0; +var filex = new Float32Array(6); +var p_filex = E.getAddressOf(filex, true); +var addr = new Int32Array(12); +var p_addr = E.getAddressOf(addr, true); +var polyp = new Int32Array(6); +var p_polyp = E.getAddressOf(polyp, true); +var polyedge = new Int32Array(8); +var p_polyedge = E.getAddressOf(polyedge, true); +var edges; +var p_edges; +var zbuf; +var p_zbuf; +var zDist; +var points; +var p_points; +var rpoints; +var p_rpoints; +var npoints = 0; +var faces; +var p_faces; +var vpoints; +var p_vpoints; +var normals; +var p_normals; +var rnormals; +var p_rnormals; +var lastTime; +var nFrames = 0; +var interv; +var qZrot = 0; +var qWireframe = 0; +var zBeta = 0; + +const c05 = Math.cos(0.05); +const s05 = Math.sin(0.05); + +var c = (function(){ + var bin=atob("8e4QCnBHAAACS9P4BAHA84AQcEcA4QDg8e4QOiPwnwPh7hA68e4QOgJLQCLD+IQhcEcAvwDhAOCf7SN63+0jahC1ACMERpNCke0AajDa1O0Aenfuxnr07sd68e4Q+iTV9O7mevHuEPof3dTtAXqR7QFqd+7GevTux3rx7hD6FNX07uZ68e4Q+g/d1O0CepHtAmp37sZ69O7HevHuEPoE1fTu5nrx7hD6DNwBMww0yucMIwP7AgCA7QBqS2hDYItog2ATRhhGEL0Xt9E4F7fRuC3p8E/Q+BywQ2mf7Tt6BWiHsFhGAZEDkwAiT/AGCAGbmkJl2gLrQgMFkwj7AlMCkwAjHEZfHAMhl/vx/gWZAp4O604Op+sODk/wAQyORDb5E2A1+R7gDPoD81uy3fgEwASTDPH/M7zxAA8H0QMvO0bg0QObDDDUVAEy0OeaQjXQCPsD/AXrDAq6+QKQTkUD0TX5DBBxRQvQuvkEoFZFAdHORQXQNfkMwLRFH9HWRR3RDCEB+wOz0O0BatPtAXqT7QBqZ+6metDtAGrm7iZ6k+0CatDtAmrm7iZ69O7HevHuEPoC1QSbHEPksgAjnEa45wewvejwjwC/MzNzPy3p8ENEaAVo0PgIwMNoB2nB8wkBDCYG+wFE1O0CevXuwHrx7hD6QPO8gND4FICAaQHrQQ4F604OACU++QJrPPkmkEX4A5AM64YGA+sFCQg1tvkCYMn4BGAYLe7RACor0Bj4ASABOgYqAPKSgN/oAvAEFG5UeIRhABpoAmBaaEJgmmiCYNpowmAaaAJhWmhCYZpogmHbaA7gmmgCYNpoQmAaaYJgWmnCYJpoAmHaaEJhGmmCYVtpw2GU7QBq1+0AarfuAHqm7iZ61+0BapTtAWqm7iZ61+0Caqfupnrf7TJqx+4mep/tMXp37od6s+4Peifuh3q97sd6F+4QCp/tLHpn7od6wwL97ud6F+6QKkPqQhMYQ73o8IMaaQJgWmlCYBpogmBaaMJgGmkCYVppQmEI4BofA/EUAcUaUvgEb65QkUL60RpogmFbaLTnGh8D8RQBxRpS+ARvrlCRQvrRp+caaQJgWmlCYBpogmBaaMJgmmgCYdpoiueaaAJg2mhCYBppgmBaacJgGmgCYVpozucDH0/w/zIcMEP4BC+YQvvRiucAIL3o8IOamTlAzcxMPgAAfEIt6fBBBEYORgEuNdlzHiJGACHS+ACABOuBAAdGUPgEW0VFAd2ZQgrTBOuDDGBGXPgE6fBFBd2ZQhTSATv25wEx6+eZQg7SdUUM0JdCCNCQQgi/OkbH+ADgBWANRilG2OcCRvfnTRyrQvjYIEb/98j/BOuFBHYbx+e96PCBn+0XevC0ACUMJp1CAfEGASHaMfgETDH4BnwG+wQE1O0CajH4AkwG+wcH1+0Cegb7BAR37qZ61O0Canfupnpn7od6/e7nehfukEpF6oQkQvglQAE12ecZRhBG8Lz/95K/AAB6RAfukDq47ud63+0aep/tGmqf7Rpa3+0aWsfuJ0oQtQAklEIA8QwAAfEEASHaATQQ7QF6UO0DajfuZHpm7oZqxu6HelDtAmp37oV6Zu6Gav3u53oX7pA6xu6HeiH4BDx37qV6/e7nehfukDoh+AI81+cQvQC/AADIQgAAoEMAAPBCAACgQpPtA1rT7QRaELX37gBKACSUQgDxDAAB8QwBedqT7QBqk+0CStPtAWp07sV6Zu4mOiTuZXqw7kU6p+6jegE0UO0COifuI3pm7gY6Ze6maqPupzom7gRq8O5DOhDtAzrn7oZqo+4jehDtAWqm7iZ6sO5FSgHtA3qT7QFq0+0COtPtAGom7gZ6Ju4mOqfuh0om7iNqsO5EehDtAkon7gR6Je6jSmbu5Wqn7oNKEO0DOufuhmqj7gR6EO0BaqbuJnoB7QJ60+0CapPtAEqT7QFqJe6Eembuhjom7oRKp+6jeibuZWpQ7QI6p+6EaifuI3oQ7QNKZu6maqTuBnqw7kVqp+6malDtAWqm7oZ6Ae0Ben/nEL0AAA=="); + return { + rotatePoints:E.nativeCall(1253, "void(int, int, int, int)", bin), + projectPoints:E.nativeCall(1121, "void(int, int, int, int)", bin), + popZBuf:E.nativeCall(1021, "void(int, int, int, int)", bin), + processFace:E.nativeCall(461, "int(int, int, int)", bin), + initEdges:E.nativeCall(209, "void(int, int)", bin), + findSlot:E.nativeCall(57, "int(int, int, int)", bin), + clearFPU:E.nativeCall(25, "void()", bin), + getFPSCR:E.nativeCall(1, "int()", bin), + getFPUPendingIRQ:E.nativeCall(9, "int()", bin), + }; +})(); + +function initNormals() { + var i = faces.length/3; + while (i--) { + normals[i*3+0] = (points[faces[3*i+1]*3+1]-points[faces[3*i+0]*3+1])*(points[faces[3*i+2]*3+2]-points[faces[3*i+0]*3+2]) - (points[faces[3*i+1]*3+2]-points[faces[3*i+0]*3+2])*(points[faces[3*i+2]*3+1]-points[faces[3*i+0]*3+1]); + normals[i*3+1] = (points[faces[3*i+1]*3+2]-points[faces[3*i+0]*3+2])*(points[faces[3*i+2]*3+0]-points[faces[3*i+0]*3+0]) - (points[faces[3*i+1]*3+0]-points[faces[3*i+0]*3+0])*(points[faces[3*i+2]*3+2]-points[faces[3*i+0]*3+2]); + normals[i*3+2] = (points[faces[3*i+1]*3+0]-points[faces[3*i+0]*3+0])*(points[faces[3*i+2]*3+1]-points[faces[3*i+0]*3+1]) - (points[faces[3*i+1]*3+1]-points[faces[3*i+0]*3+1])*(points[faces[3*i+2]*3+0]-points[faces[3*i+0]*3+0]); + var n = Math.sqrt(normals[i*3]*normals[i*3]+normals[i*3+1]*normals[i*3+1]+normals[i*3+2]*normals[i*3+2]); + if (n>0) { + normals[i*3] /= -n; + normals[i*3+1] /= -n; + normals[i*3+2] /= -n; + } + } +} + +function readSTL(fn) { + var fb = require("Storage").read(fn); + var nverts=0,i=0; while((i=fb.indexOf("vertex",i)+1)!=0) nverts++; + points = new Float32Array(nverts); + p_points = E.getAddressOf(points, true); + faces = new Uint16Array(nverts); + p_faces = E.getAddressOf(faces, true); + edges = new Uint8Array(Math.max(faces.length/3,24)) + p_edges = E.getAddressOf(edges, true); + var fp=0, p=0; + var nf = 0; + g.setColor(0.9, 0.9, 0.9); + g.drawRect(20, 140, 220, 160); + g.setColor(0.6, 0.6, 0.9); + while (p<fb.length) { + var line = ''; + while (fb[p]!="\n") line += fb[p++]; + p++; + if (line.toLowerCase().includes("vertex")) { + var v = line.trim().split(/\s+/); + filex[0] = v[1]; + filex[1] = v[3]; + filex[2] = v[2]; + var slot = 0|c.findSlot(p_points, p_filex, npoints); + if (slot==npoints) npoints++; + faces[fp++] = slot; + if (fp%3 == 0) g.fillRect(21, 141, 21+198*fp/nverts, 159); + } + } + vpoints = new Uint16Array(Math.max(12,2*npoints)); + p_vpoints = E.getAddressOf(vpoints, true); + normals = new Float32Array(faces.length); + p_normals = E.getAddressOf(normals, true); + initNormals(); + rnormals = new Float32Array(faces.length); + p_rnormals = E.getAddressOf(rnormals, true); + rpoints = new Float32Array(points.length); + p_rpoints = E.getAddressOf(rpoints, true); + zbuf = new Int32Array(Math.max(12,faces.length/3)); + p_zbuf = E.getAddressOf(zbuf, true); + addr[0] = p_faces; + addr[1] = p_rnormals; + addr[2] = p_vpoints; + addr[3] = p_polyp; + addr[4] = p_light; + addr[5] = p_edges; + addr[6] = p_polyedge; + addr[7] = p_normals; + c.initEdges(p_addr, faces.length/3); +} + +function rotV(v, u, c, s) { + "ram" + return [v[0]*(c+u[0]*u[0]*(1-c)) + v[1]*(u[0]*u[1]*(1-c)-u[2]*s) + v[2]*(u[0]*u[2]*(1-c)+u[1]*s), + v[0]*(u[1]*u[0]*(1-c)+u[2]*s) + v[1]*(c+u[1]*u[1]*(1-c)) + v[2]*(u[1]*u[2]*(1-c)-u[0]*s), + v[0]*(u[2]*u[0]*(1-c)-u[1]*s) + v[1]*(u[2]*u[1]*(1-c)+u[0]*s) + v[2]*(c+u[2]*u[2]*(1-c))]; +} + +function largestExtent(pts) { + var x = 0; + var i = pts.length/3; + while (i--) { + var e = pts[3*i]*pts[3*i]+pts[3*i+1]*pts[3*i+1]+pts[3*i+2]*pts[3*i+2]; + if (e>x) x = e; + } + return Math.sqrt(x); +} + +function draw() { + "ram" + const n = [1, 0, 0]; + if (qZrot>0) { + var ca, sa, cb, sb; + if (qZrot==2) { + var acc = Bangle.getAccel(); + zBeta = -Math.atan2(acc.z, -acc.y); + var comp = Bangle.getCompass(); + if (!isNaN(comp.heading)) { + var m = [comp.dx, comp.dy, comp.dz]; + //console.log(m); + var rm = rotV(m, [1, 0, 0], Math.cos(zBeta), Math.sin(zBeta)); + a = -Math.atan2(rm[0], rm[2]); + //console.log("heading="+a*180/Math.PI, "zBeta="+zBeta); + } + else a = 0; + } + ca=Math.cos(a); sa=Math.sin(a); cb=Math.cos(zBeta); sb=Math.sin(zBeta); + var ul = Math.sqrt(sb*sb+ca*ca*sb*sb+2*sa*sa*cb+2*ca*sb*sb+2*sa*sa); + u = [(sb+ca*sb)/ul, (-sa-sa*cb)/ul, (-sa*sb)/ul]; + var ra = Math.acos((ca+cb+ca*cb-1)/2); + if (ra<0) ra += Math.PI; + aux[3] = Math.cos(ra); + aux[4] = Math.sin(ra); + } + else{ + u = rotV(u, n, c05, s05); + aux[3] = Math.cos(a); + aux[4] = Math.sin(a); + } + a += 0.08; + aux[0] = u[0]; aux[1]=u[1]; aux[2]=u[2]; + c.rotatePoints(p_points, p_rpoints, npoints, p_aux); + c.rotatePoints(p_normals, p_rnormals, faces.length/3, p_aux); + c.projectPoints(p_rpoints, p_vpoints, npoints, 0|zDist*100); + c.popZBuf(p_rpoints, p_faces, p_zbuf, faces.length/3); + g.clear(); + var z, shade; + if (qWireframe>0) { + var i = faces.length/3; + while (i--) { + z = zbuf[i]; + shade = 0|c.processFace(p_addr, z, 1); + if (shade > 0) { + if (qWireframe==1) g.setColor(shade).fillPoly(polyp).setColor(0).drawPoly(polyedge); + else { + g.setColor(0).fillPoly(polyp).setColor(shade); + if (qWireframe==2) g.drawPoly(polyedge); + else g.drawPoly(polyp, true); + } + } + } + } + else { + var i = faces.length/3; + while (i--) { + z = zbuf[i]; + shade = 0|c.processFace(p_addr, z, 0); + if (shade > 0) g.setColor(shade).fillPoly(polyp); + } + } + nFrames++; + var fps = Math.round(nFrames*100000/(Date.now()-lastTime))/100; + g.setColor(0.7, 0.7, 0.7); + g.setFont("6x8", 1); + g.drawString("fps:"+fps.toString(), 20, 0); + g.flip(); +} + +function loadFile(fn) { + Bangle.setLCDMode("direct"); + g.clear(); + E.showMenu(); + E.showMessage("Loading...", fn); + readSTL(fn); + zDist = 5*largestExtent(points); + g.clear(); + g.setColor(1, 1, 1); + g.setFont("6x8", 2); + g.setFontAlign(-1, -1); + g.setColor(1, 0.5, 0.5); + g.drawString("Model info",15, 40); + g.setColor(1, 1, 1); + g.drawString("# faces: "+faces.length/3, 15, 80); + g.drawString("# vertices: "+npoints, 15, 110); + g.drawString("max extent: "+Math.round(100*(zDist/5))/100, 15, 140); + g.flip(); + setWatch(function() { + if (interv) { + interv = clearInterval(interv); + load(); + } + else { + Bangle.setLCDMode("doublebuffered"); + lastTime = Date.now(); + nFrames = 0; + interv = setInterval(function() { draw();}, 30); + } }, BTN2, {repeat:true, debounce:50}); + setWatch(function() { + if (qZrot==1) { + if (zBeta<2*Math.PI/2-0.08) zBeta += 0.08; + } else zDist *= 0.9; + }, BTN1, {repeat:true}); + setWatch(function() { + if (qZrot==1) { + if (zBeta>-2*Math.PI/2-0.08) zBeta -= 0.08; + } else zDist /= 0.9; + }, BTN3, {repeat:true}); + Bangle.on('swipe', function(direction){ + switch(direction){ + case 1: + qZrot = (qZrot+1)%3; + break; + case -1: + qWireframe = (qWireframe+1)%4; + break; + }}); +} + +function drawMenu() { + const menu = { + '': { 'title': 'STL files' } + }; + var files = require("Storage").list(".stl"); + for (var i=0; i<files.length; ++i) { + menu[files[i]] = loadFile.bind(null, files[i]); + } + menu['Exit'] = function() { load(); }; + E.showMenu(menu); +} + +Bangle.on('kill',()=>{Bangle.setCompassPower(0);}); +Bangle.setCompassPower(1); +drawMenu(); diff --git a/apps/wclock/clock-word.js b/apps/wclock/clock-word.js index 00b262ef7..b8c36f548 100644 --- a/apps/wclock/clock-word.js +++ b/apps/wclock/clock-word.js @@ -1,39 +1,39 @@ /* jshint esversion: 6 */ const allWords = [ - "ATWENTYD", - "QUARTERY", - "FIVEHALF", - "DPASTORO", - "FIVEIGHT", - "SIXTHREE", - "TWELEVEN", - "FOURNINE" + "ATWENTYD", + "QUARTERY", + "FIVEHALF", + "DPASTORO", + "FIVEIGHT", + "SIXTHREE", + "TWELEVEN", + "FOURNINE" ]; const hours = { - 0: ["", 0, 0], - 1: ["ONE", 17, 47, 77], - 2: ["TWO", 06, 16, 17], - 3: ["THREE", 35, 45, 55, 65, 75], - 4: ["FOUR", 07, 17, 27, 37], - 5: ["FIVE", 04, 14, 24, 34], - 6: ["SIX", 05, 15, 25], - 7: ["SEVEN", 05, 46, 56, 66, 67], - 8: ["EIGHT", 34, 44, 54, 64, 74], - 9: ["NINE", 47, 57, 67, 77], - 10: ["TEN", 74, 75, 76], - 11: ["ELEVEN", 26, 36, 46, 56, 66, 76], - 12: ["TWELVE", 06, 16, 26, 36, 56, 66] + 0: ["", 0, 0], + 1: ["ONE", 17, 47, 77], + 2: ["TWO", 06, 16, 17], + 3: ["THREE", 35, 45, 55, 65, 75], + 4: ["FOUR", 07, 17, 27, 37], + 5: ["FIVE", 04, 14, 24, 34], + 6: ["SIX", 05, 15, 25], + 7: ["SEVEN", 05, 46, 56, 66, 67], + 8: ["EIGHT", 34, 44, 54, 64, 74], + 9: ["NINE", 47, 57, 67, 77], + 10: ["TEN", 74, 75, 76], + 11: ["ELEVEN", 26, 36, 46, 56, 66, 76], + 12: ["TWELVE", 06, 16, 26, 36, 56, 66] }; const mins = { - 0: ["A", 0, 0], - 1: ["FIVE", 02, 12, 22, 32], - 2: ["TEN", 10, 30, 40], - 3: ["QUARTER", 01, 11, 21, 31, 41, 51, 61], - 4: ["TWENTY", 10, 20, 30, 40, 50, 60], - 5: ["HALF", 42, 52, 62, 72], - 6: ["PAST", 13, 23, 33, 43], - 7: ["TO", 43, 53] + 0: ["A", 0, 0], + 1: ["FIVE", 02, 12, 22, 32], + 2: ["TEN", 10, 30, 40], + 3: ["QUARTER", 01, 11, 21, 31, 41, 51, 61], + 4: ["TWENTY", 10, 20, 30, 40, 50, 60], + 5: ["HALF", 42, 52, 62, 72], + 6: ["PAST", 13, 23, 33, 43], + 7: ["TO", 43, 53] }; // offsets and incerments @@ -49,71 +49,71 @@ const activeColor = 0xF800 /*red*/ ; function drawWordClock() { - // get time - var t = new Date(); - var h = t.getHours(); - var m = t.getMinutes(); - var time = ("0" + h).substr(-2) + ":" + ("0" + m).substr(-2); + // get time + var t = new Date(); + var h = t.getHours(); + var m = t.getMinutes(); + var time = ("0" + h).substr(-2) + ":" + ("0" + m).substr(-2); - var hidx; - var midx; - var midxA = []; + var hidx; + var midx; + var midxA = []; - g.setFont("6x8",fontSize); - g.setColor(passivColor); - g.setFontAlign(0, -1, 0); + g.setFont("6x8",fontSize); + g.setColor(passivColor); + g.setFontAlign(0, -1, 0); - // draw allWords - var c; - var y = ys; - var x = xs; - allWords.forEach((line) => { - x = xs; - for (c in line) { - g.drawString(line[c], x, y); - x += dx; - } - y += dy; - }); - - // calc indexes - midx = Math.round(m / 5); - hidx = h % 12; - if (hidx === 0) { hidx = 12; } - if (midx > 6) { - if (midx == 12) { midx = 0; } - hidx++; + // draw allWords + var c; + var y = ys; + var x = xs; + allWords.forEach((line) => { + x = xs; + for (c in line) { + g.drawString(line[c], x, y); + x += dx; } - if (midx !== 0) { - if (midx <= 6) { - midxA = [midx, 6]; - } else { - midxA = [12 - midx, 7]; - } + y += dy; + }); + + // calc indexes + midx = Math.round(m / 5); + hidx = h % 12; + if (hidx === 0) { hidx = 12; } + if (midx > 6) { + if (midx == 12) { midx = 0; } + hidx++; + } + if (midx !== 0) { + if (midx <= 6) { + midxA = [midx, 6]; + } else { + midxA = [12 - midx, 7]; } + } - // write hour in active color - g.setColor(activeColor); - hours[hidx][0].split('').forEach((c, pos) => { - x = xs + (hours[hidx][pos + 1] / 10 | 0) * dx; - y = ys + (hours[hidx][pos + 1] % 10) * dy; + // write hour in active color + g.setColor(activeColor); + hours[hidx][0].split('').forEach((c, pos) => { + x = xs + (hours[hidx][pos + 1] / 10 | 0) * dx; + y = ys + (hours[hidx][pos + 1] % 10) * dy; - g.drawString(c, x, y); + g.drawString(c, x, y); + }); + + // write min words in active color + midxA.forEach(idx => { + mins[idx][0].split('').forEach((c, pos) => { + x = xs + (mins[idx][pos + 1] / 10 | 0) * dx; + y = ys + (mins[idx][pos + 1] % 10) * dy; + g.drawString(c, x, y); }); + }); - // write min words in active color - midxA.forEach(idx => { - mins[idx][0].split('').forEach((c, pos) => { - x = xs + (mins[idx][pos + 1] / 10 | 0) * dx; - y = ys + (mins[idx][pos + 1] % 10) * dy; - g.drawString(c, x, y); - }); - }); - - // display digital time - g.setColor(activeColor); - g.clearRect(0, 215, 240, 240); - g.drawString(time, 120, 215); + // display digital time + g.setColor(activeColor); + g.clearRect(0, 215, 240, 240); + g.drawString(time, 120, 215); } Bangle.on('lcdPower', function(on) { diff --git a/apps/weather/ChangeLog b/apps/weather/ChangeLog new file mode 100644 index 000000000..5e27e1bf4 --- /dev/null +++ b/apps/weather/ChangeLog @@ -0,0 +1,2 @@ +0.02: Make minor adjustments to widget, and discard stale weather data after a configurable period. +0.03: Fix flickering last updated time. \ No newline at end of file diff --git a/apps/weather/app.js b/apps/weather/app.js new file mode 100644 index 000000000..ea8936886 --- /dev/null +++ b/apps/weather/app.js @@ -0,0 +1,87 @@ +(() => { + const weather = require('weather'); + + function formatDuration(millis) { + let pluralize = (n, w) => n + " " + w + (n == 1 ? "" : "s"); + if (millis < 60000) return "< 1 minute"; + if (millis < 3600000) return pluralize(Math.floor(millis/60000), "minute"); + if (millis < 86400000) return pluralize(Math.floor(millis/3600000), "hour"); + return pluralize(Math.floor(millis/86400000), "day"); + } + + function draw() { + let w = weather.current; + g.reset(); + g.setColor(0).fillRect(0, 24, 239, 239); + + weather.drawIcon(w.txt, 65, 90, 55); + const locale = require("locale"); + + g.setColor(-1); + + const temp = locale.temp(w.temp-273.15).match(/^(\D*\d*)(.*)$/); + let width = g.setFont("Vector", 40).stringWidth(temp[1]); + width += g.setFont("Vector", 20).stringWidth(temp[2]); + g.setFont("Vector", 40).setFontAlign(-1, -1, 0); + g.drawString(temp[1], 180-width/2, 70); + g.setFont("Vector", 20).setFontAlign(1, -1, 0); + g.drawString(temp[2], 180+width/2, 70); + + g.setFont("6x8", 1); + g.setFontAlign(-1, 0, 0); + g.drawString("Humidity", 135, 130); + g.drawString("Wind", 135, 142); + g.setFontAlign(1, 0, 0); + g.drawString(w.hum+"%", 225, 130); + g.drawString(locale.speed(w.wind), 225, 142); + + g.setFont("6x8", 2).setFontAlign(0, 0, 0); + g.drawString(w.loc, 120, 170); + + g.setFont("6x8", 1).setFontAlign(0, 0, 0); + g.drawString(w.txt.charAt(0).toUpperCase()+w.txt.slice(1), 120, 190); + + drawUpdateTime(); + + g.flip(); + } + + function drawUpdateTime() { + if (!weather.current || !weather.current.time) return; + let text = `Last update received ${formatDuration(Date.now() - weather.current.time)} ago`; + g.reset(); + g.setColor(0).fillRect(0, 202, 239, 210); + g.setColor(-1).setFont("6x8", 1).setFontAlign(0, 0, 0); + g.drawString(text, 120, 206); + } + + function update() { + if (weather.current) { + draw(); + } else { + E.showMessage('Weather unknown\n\nIs Gadgetbridge\nconnected?'); + } + } + + let interval = setInterval(drawUpdateTime, 60000); + Bangle.on('lcdPower', (on) => { + if (interval) { + clearInterval(interval); + interval = undefined; + } + if (on) { + drawUpdateTime(); + interval = setInterval(drawUpdateTime, 60000); + } + }); + + weather.on("update", update); + + update(weather.current); + + // Show launcher when middle button pressed + setWatch(Bangle.showLauncher, BTN2, {repeat: false, edge: 'falling'}); + + Bangle.loadWidgets(); + Bangle.drawWidgets(); +})() diff --git a/apps/weather/icon.js b/apps/weather/icon.js new file mode 100644 index 000000000..18ca2b0c9 --- /dev/null +++ b/apps/weather/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AE8N6AXV7vdFyoXBGCQUBAAoXp73u93tC6YWBAAIXSFwQwDRiAWDGASSBmYABIx5IDgYXCmC7KCoYRBnvUCwQwKC4gSEAAgwKC5gwKCwPjC6inBC6owBC6wVKPBXd6YXMDBAuNJJQXWfwZITC/6QIBw073ezR6m73anOJAwuHeBAYFIw4WJAAsL3YQOAAxeBCiWIC4e72AJChGACpMIxAXBIwIwEBIIXKBgouDEIYuLC4ghEC6ELLoYXPU4YXFLxQNBBgcLEQqqQFwYA/AH4AYA==")) diff --git a/apps/weather/icon.png b/apps/weather/icon.png new file mode 100644 index 000000000..bbfc0ace0 Binary files /dev/null and b/apps/weather/icon.png differ diff --git a/apps/weather/lib.js b/apps/weather/lib.js new file mode 100644 index 000000000..fffc523ca --- /dev/null +++ b/apps/weather/lib.js @@ -0,0 +1,215 @@ +const storage = require('Storage'); + +let expiryTimeout = undefined; +function scheduleExpiry(json) { + if (expiryTimeout) { + clearTimeout(expiryTimeout); + expiryTimeout = undefined; + } + let expiry = "expiry" in json ? json.expiry : 2*3600000; + if (json.weather && json.weather.time && expiry) { + let t = json.weather.time + expiry - Date.now(); + expiryTimeout = setTimeout(() => { + expiryTimeout = undefined; + + let json = storage.readJSON('weather.json')||{}; + delete json.weather; + storage.write('weather.json', json); + + exports.current = undefined; + exports.emit("update"); + }, t); + } +} + +function setCurrentWeather(json) { + scheduleExpiry(json); + exports.current = json.weather; +} + +function update(weatherEvent) { + let weather = Object.assign({}, weatherEvent); + weather.time = Date.now(); + delete weather.t; + + let json = storage.readJSON('weather.json')||{}; + json.weather = weather; + storage.write('weather.json', json); + + setCurrentWeather(json); + + exports.emit("update"); +} + +const _GB = global.GB; +global.GB = (event) => { + if (event.t==="weather") update(event); + if (_GB) setTimeout(_GB, 0, event); +}; + +setCurrentWeather(storage.readJSON('weather.json')||{}); + +exports.drawIcon = function(cond, x, y, r) { + function drawSun(x, y, r) { + g.setColor("#FF7700"); + g.fillCircle(x, y, r); + } + + function drawCloud(x, y, r, c) { + const u = r/12; + if (c==null) c = "#EEEEEE"; + g.setColor(c); + g.fillCircle(x-8*u, y+3*u, 4*u); + g.fillCircle(x-4*u, y-2*u, 5*u); + g.fillCircle(x+4*u, y+0*u, 4*u); + g.fillCircle(x+9*u, y+4*u, 3*u); + g.fillPoly([ + x-8*u, y+7*u, + x-8*u, y+3*u, + x-4*u, y-2*u, + x+4*u, y+0*u, + x+9*u, y+4*u, + x+9*u, y+7*u, + ]); + } + + function drawBrokenClouds(x, y, r) { + drawCloud(x+1/8*r, y-1/8*r, 7/8*r, "#777777"); + drawCloud(x-1/8*r, y+1/8*r, 7/8*r); + } + + function drawFewClouds(x, y, r) { + drawSun(x+3/8*r, y-1/8*r, 5/8*r); + drawCloud(x-1/8*r, y+1/8*r, 7/8*r); + } + + function drawRainLines(x, y, r) { + g.setColor("#FFFFFF"); + const y1 = y+1/2*r; + const y2 = y+1*r; + g.fillPoly([ + x-6/12*r+1, y1, + x-8/12*r+1, y2, + x-7/12*r, y2, + x-5/12*r, y1, + ]); + g.fillPoly([ + x-2/12*r+1, y1, + x-4/12*r+1, y2, + x-3/12*r, y2, + x-1/12*r, y1, + ]); + g.fillPoly([ + x+2/12*r+1, y1, + x+0/12*r+1, y2, + x+1/12*r, y2, + x+3/12*r, y1, + ]); + } + + function drawShowerRain(x, y, r) { + drawFewClouds(x, y-1/3*r, r); + drawRainLines(x, y, r); + } + + function drawRain(x, y, r) { + drawBrokenClouds(x, y-1/3*r, r); + drawRainLines(x, y, r); + } + + function drawThunderstorm(x, y, r) { + function drawLightning(x, y, r) { + g.setColor("#FF7700"); + g.fillPoly([ + x-2/6*r, y-r, + x-4/6*r, y+1/6*r, + x-1/6*r, y+1/6*r, + x-3/6*r, y+1*r, + x+3/6*r, y-1/6*r, + x+0/6*r, y-1/6*r, + x+3/6*r, y-r, + ]); + } + + drawBrokenClouds(x, y-1/3*r, r); + drawLightning(x-1/12*r, y+1/2*r, 1/2*r); + } + + function drawSnow(x, y, r) { + function rotatePoints(points, pivotX, pivotY, angle) { + for(let i = 0; i<points.length; i += 2) { + const x = points[i]; + const y = points[i+1]; + points[i] = Math.cos(angle)*(x-pivotX)-Math.sin(angle)*(y-pivotY)+ + pivotX; + points[i+1] = Math.sin(angle)*(x-pivotX)+Math.cos(angle)*(y-pivotY)+ + pivotY; + } + } + + g.setColor("#FFFFFF"); + const w = 1/12*r; + for(let i = 0; i<=6; ++i) { + const points = [ + x+w, y, + x-w, y, + x-w, y+r, + x+w, y+r, + ]; + rotatePoints(points, x, y, i/3*Math.PI); + g.fillPoly(points); + + for(let j = -1; j<=1; j += 2) { + const points = [ + x+w, y+7/12*r, + x-w, y+7/12*r, + x-w, y+r, + x+w, y+r, + ]; + rotatePoints(points, x, y+7/12*r, j/3*Math.PI); + rotatePoints(points, x, y, i/3*Math.PI); + g.fillPoly(points); + } + } + } + + function drawMist(x, y, r) { + const layers = [ + [-0.4, 0.5], + [-0.8, 0.3], + [-0.2, 0.9], + [-0.9, 0.7], + [-0.2, 0.3], + ]; + + g.setColor("#FFFFFF"); + for(let i = 0; i<5; ++i) { + g.fillRect(x+layers[i][0]*r, y+(0.4*i-0.9)*r, x+layers[i][1]*r, + y+(0.4*i-0.7)*r-1); + g.fillCircle(x+layers[i][0]*r, y+(0.4*i-0.8)*r-0.5, 0.1*r-0.5); + g.fillCircle(x+layers[i][1]*r, y+(0.4*i-0.8)*r-0.5, 0.1*r-0.5); + } + } + + function chooseIcon(condition) { + if (!condition) return () => {}; + condition = condition.toLowerCase(); + if (condition.includes("thunderstorm")) return drawThunderstorm; + if (condition.includes("freezing")||condition.includes("snow")|| + condition.includes("sleet")) { + return drawSnow; + } + if (condition.includes("drizzle")|| + condition.includes("shower")) { + return drawRain; + } + if (condition.includes("rain")) return drawShowerRain; + if (condition.includes("clear")) return drawSun; + if (condition.includes("few clouds")) return drawFewClouds; + if (condition.includes("scattered clouds")) return drawCloud; + if (condition.includes("clouds")) return drawBrokenClouds; + return drawMist; + } + + chooseIcon(cond)(x, y, r); +}; diff --git a/apps/weather/readme.md b/apps/weather/readme.md new file mode 100644 index 000000000..a326b67dd --- /dev/null +++ b/apps/weather/readme.md @@ -0,0 +1,16 @@ +# Weather + +Shows Gadgetbridge weather reports. + +This adds a widget with a weather pictogram and the temperature. +You can view the full report through the app: +![Screenshot](screenshot.png) + +## Setup + +See [this guide](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Weather) +to setup Gadgetbridge weather reporting. + +## Controls + +BTN2: opens the launcher diff --git a/apps/weather/screenshot.png b/apps/weather/screenshot.png new file mode 100644 index 000000000..ce79b3b64 Binary files /dev/null and b/apps/weather/screenshot.png differ diff --git a/apps/weather/settings.js b/apps/weather/settings.js new file mode 100644 index 000000000..1cc097e3a --- /dev/null +++ b/apps/weather/settings.js @@ -0,0 +1,24 @@ +(function(back) { + const storage = require('Storage'); + let settings = storage.readJSON('weather.json', 1) || {}; + function save(key, value) { + settings[key] = value; + storage.write('weather.json', settings); + } + E.showMenu({ + '': { 'title': 'Weather' }, + 'Expiry': { + value: "expiry" in settings ? settings["expiry"] : 2*3600000, + min: 0, + max : 24*3600000, + step: 15*60000, + format: x => { + if (x == 0) return "none"; + if (x < 3600000) return Math.floor(x/60000) + "m"; + if (x < 86400000) return Math.floor(x/36000)/100 + "h"; + }, + onchange: x => save('expiry', x), + }, + '< Back': back, + }); +}) diff --git a/apps/weather/widget.js b/apps/weather/widget.js new file mode 100644 index 000000000..eb5ead949 --- /dev/null +++ b/apps/weather/widget.js @@ -0,0 +1,57 @@ +(() => { + const weather = require('weather'); + + function draw() { + const w = weather.current; + if (!w) return; + g.reset(); + g.setColor(0).fillRect(this.x, this.y, this.x+this.width-1, this.y+23); + if (w.txt) { + weather.drawIcon(w.txt, this.x+10, this.y+8, 7.5); + } + if (w.temp) { + let t = require('locale').temp(w.temp-273.15); // applies conversion + t = t.match(/[\d\-]*/)[0]; // but we have no room for units + g.setFontAlign(0, 1); // center horizontally at bottom of widget + g.setFont('6x8', 1); + g.setColor(-1); + g.drawString(t, this.x+10, this.y+24); + } + } + + var dirty = false; + + function update() { + if (!WIDGETS["weather"].width) { + WIDGETS["weather"].width = 20; + Bangle.drawWidgets(); + } else if (Bangle.isLCDOn()) { + WIDGETS["weather"].draw(); + } else { + dirty = true; + } + } + + function hide() { + WIDGETS["weather"].width = 0; + Bangle.drawWidgets(); + } + + weather.on("update", () => { + if (weather.current) update(); + else hide(); + }); + + Bangle.on('lcdPower', on => { + if (on && dirty) { + WIDGETS["weather"].draw(); + dirty = false; + } + }); + + WIDGETS["weather"] = { + area: "tl", + width: weather.current ? 20 : 0, + draw: draw, + }; +})(); diff --git a/apps/welcome/ChangeLog b/apps/welcome/ChangeLog index b8786af6a..9545dbbfa 100644 --- a/apps/welcome/ChangeLog +++ b/apps/welcome/ChangeLog @@ -7,3 +7,7 @@ 0.07: Run again when updated Don't run again when settings app is updated (or absent) Add "Run Now" option to settings +0.08: Don't overwrite existing settings on app update +0.09: Allow welcome to run after a fresh install + More useful app menu + BTN2 now goes to menu on release diff --git a/apps/welcome/app.js b/apps/welcome/app.js index a32a6e56f..8cbdc2efa 100644 --- a/apps/welcome/app.js +++ b/apps/welcome/app.js @@ -87,7 +87,7 @@ var scenes = [ ()=>{g.setFont("Vector",36);g.drawString("1",200,40);}, ()=>g.drawString("2",200,120), ()=>g.drawString("3",200,200) - ],200); + ],200); }, function() { g.reset(); @@ -138,15 +138,15 @@ var scenes = [ var x = 120, y = 10, h=21; animate([ ()=>{g.drawString("Bangle.js has a",x,y+=h); - g.drawString("simple touchscreen",x,y+=h);}, + g.drawString("simple touchscreen",x,y+=h);}, 0,0, ()=>{g.drawString("It'll detect touch",x,y+=h*2); - g.drawString("on left and right",x,y+=h);}, + g.drawString("on left and right",x,y+=h);}, 0,0, ()=>{g.drawString("Horizontal swipes",x,y+=h*2); - g.drawString("work too. Try now",x,y+=h); - g.drawString("to change page.",x,y+=h);} - ],300); + g.drawString("work too. Try now",x,y+=h); + g.drawString("to change page.",x,y+=h);} + ],300); }, function() { g.reset(); @@ -156,15 +156,15 @@ var scenes = [ var x = 120, y = 10, h=21; animate([ ()=>{g.drawString("Bangle.js",x,y+=h); - g.drawString("comes with",x,y+=h); - g.drawString("a few simple",x,y+=h); - g.drawString("apps installed",x,y+=h);}, + g.drawString("comes with",x,y+=h); + g.drawString("a few simple",x,y+=h); + g.drawString("apps installed",x,y+=h);}, 0,0, ()=>{g.drawString("To add more, visit",x,y+=h*2); - g.drawString("banglejs.com/apps",x,y+=h); - g.drawString("with a Bluetooth",x,y+=h); - g.drawString("capable device",x,y+=h);}, - ],400); + g.drawString("banglejs.com/apps",x,y+=h); + g.drawString("with a Bluetooth",x,y+=h); + g.drawString("capable device",x,y+=h);}, + ],400); }, function() { g.reset(); @@ -186,9 +186,9 @@ var scenes = [ rx += 0.1; ry += 0.11; var rcx=Math.cos(rx), - rsx=Math.sin(rx), - rcy=Math.cos(ry), - rsy=Math.sin(ry); + rsx=Math.sin(rx), + rcy=Math.cos(ry), + rsy=Math.sin(ry); // Project 3D coordinates into 2D function p(x,y,z) { var t; @@ -240,10 +240,10 @@ var scenes = [ animate([ ()=>g.drawString("That's it!",x,y+=h), ()=>{g.drawString("Press",x,y+=h*3); - g.drawString("Button 2",x,y+=h); - g.drawString("to start",x,y+=h); - g.drawString("Bangle.js",x,y+=h);} - ],400); + g.drawString("Button 2",x,y+=h); + g.drawString("to start",x,y+=h); + g.drawString("Bangle.js",x,y+=h);} + ],400); } ]; @@ -285,7 +285,7 @@ setWatch(()=>{ if (sceneNumber == scenes.length-1) { load(); } -}, BTN2, {repeat:true,edge:"rising"}); +}, BTN2, {repeat:true,edge:"falling"}); setWatch(()=>move(-1), BTN1, {repeat:true}); (function migrateSettings(){ diff --git a/apps/welcome/boot.js b/apps/welcome/boot.js index bc5afcc66..4e3a12231 100644 --- a/apps/welcome/boot.js +++ b/apps/welcome/boot.js @@ -1,11 +1,8 @@ (function() { - let s = require('Storage').readJSON('welcome.settings.json', 1) - || require('Storage').readJSON('setting.json', 1) - || {welcomed: true} // do NOT run if global settings are also absent - if (!s.welcomed && require('Storage').read('welcome.app.js')) { + let s = require('Storage').readJSON('welcome.json', 1) || {}; + if (!s.welcomed) { setTimeout(() => { - s.welcomed = true - require('Storage').write('welcome.settings.json', {welcomed: "yes"}) + require('Storage').write('welcome.json', {welcomed: true}) load('welcome.app.js') }) } diff --git a/apps/welcome/settings-default.json b/apps/welcome/settings-default.json deleted file mode 100644 index d250efff5..000000000 --- a/apps/welcome/settings-default.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "welcomed": false -} diff --git a/apps/welcome/settings.js b/apps/welcome/settings.js index b11921646..f269f238e 100644 --- a/apps/welcome/settings.js +++ b/apps/welcome/settings.js @@ -1,15 +1,18 @@ -// The welcome app is special, and gets to use global settings (function(back) { - let settings = require('Storage').readJSON('welcome.settings.json', 1) + let settings = require('Storage').readJSON('welcome.json', 1) || require('Storage').readJSON('setting.json', 1) || {} E.showMenu({ '': { 'title': 'Welcome App' }, - 'Run on Next Boot': { + 'Run next boot': { value: !settings.welcomed, - format: v => v ? 'OK' : 'No', - onchange: v => require('Storage').write('welcome.settings.json', {welcomed: !v}), + format: v => v ? 'Yes' : 'No', + onchange: v => require('Storage').write('welcome.json', {welcomed: !v}), }, 'Run Now': () => load('welcome.app.js'), + 'Turn off & run next': () => { + require('Storage').write('welcome.json', {welcomed: false}); + Bangle.off(); + }, '< Back': back, }) }) diff --git a/apps/widancs/ChangeLog b/apps/widancs/ChangeLog new file mode 100644 index 000000000..7844830d1 --- /dev/null +++ b/apps/widancs/ChangeLog @@ -0,0 +1,8 @@ +0.01: New Widget! +0.02: Version using connect back +0.03: Version using modified firmware +0.04: Works on both standard and modified firmware +0.05: Bug fixes w.r.t. reconnection +0.06: Update README - Release version + + diff --git a/apps/widancs/README.md b/apps/widancs/README.md new file mode 100644 index 000000000..d3ee0bdc4 --- /dev/null +++ b/apps/widancs/README.md @@ -0,0 +1,70 @@ +## ANCS - iPhone notifications for Bangle.js + +The ANCS widget allows you to answer or cancel iPhone incoming calls and also displays messages and notifications. It connects to the Apple Notification Center Service which is already on all iPhones, so you do not need to install any additional iPhone apps to use this widget. + +## Firmware +The widget will run on the standard firmware, however, installation of a slightly modified version - the zip file is available from [this directory](https://github.com/jeffmer/JeffsBangleAppsDev/tree/master/apps/widancs) - will increase the performance of the app by an order of magnitude in terms of the time to connect or reconnect to the iPhone. In addition, the Bangle will stay connected to the iPhone over a greater separation distance than with the standard firmware. + + +![](widget_pic.jpg) + +## Installation + +After the widget is uploaded to the Bangle, it needs to be enabled in the Bangle Settings app:- `ANCS Widget` will appear in `APP/Widget settings`. There is also a menu in these settings to let you configure the categories of notifications that you want to be displayed. You must disconnect from the App Loader before enabling the widget. + +## Compatible Apps + +The widget will only run with a compatible app - for the reason for this see Issue 1 below. The apps that are compatible with the ANCS widget are:- **Multi Clock**, **Navigation Compass** and **GPS Navigation**. When you switch to an app that is not compatible, the ANCS phone icon will not appear. + +## iPhone Pairing +Once enabled, the widget icon should be displayed coloured grey (its green in the photo). Go to the phone's Bluetooth settings menu and your Bangle should appear under Other devices. If this is the first time you have connected with the Bangle from your iPhone, it may be named Accessory. Click on the name and the iPhone should connect and start pairing. The widget icon will turn red and the iPhone will ask you to enter a pairing code - the traditional 123456. You have 10 seconds to enter this after which you will need to start pairing again. After that, the iPhone may also ask to allow the device access to ANCS. Once pairing is complete, the widget icon should go blue and eventually green. The range of colours is: + +* **Grey** - not connected - advertising +* **Red** - connected - not paired. +* **Blue** - paired and connected - getting services +* **Yellow** - got Services. +* **Green** - waiting for new notifications. + +After pairing the first time, the Bangle should connect automatically when the widget is running. Sometimes you may need you to click on the Bangle name in `Settings:Bluetooth:My devices` on the iPhone or disable and then enable Bluetooth to start connection. If you need to load other apps from the iPhone, it will be necessary to ask the iPhone to forget the pairing and you will also need to disable the widget in Settings and restart the Bangle by turning it off in Settings and then pressing BTN1 to restart. If you are loading apps from a different device, you simply need to turn off the iPhone bluetooth which will retain the pairing. You still need to disable the widget and restart the Bangle. + +![](message_pic.jpg) + +## Messages & Calls +Messages are displayed as shown above until BTN2 is pressed to dismiss it. I strongly advise disabling the BTN2 LCD wake function in the Settings App as otherwise when the screen times out and you press BTN2 to wake the LCD, the screen will turn on and the Message Alert will be dismissed!. Calls can be answered or dropped. + +![](call_pic.jpg) ![](missed_pic.jpg) + + +## Issues +1. With GadgetBridge, the Android phone has a Central-Client role with the Bangle as Peripheral-Server. With the ANCS widget there is the fairly unusual situation in which the Bangle is Peripheral-Client to the iPhone's Central-Server role. Since Espruino does not deal explicitly with Bangle as Peripheral-Client an additional function has been added in the modified firmware: `var gatt = NRF.getGattforCentralServer(addr);`. This returns a bluetooth remote GATT server given the address of the iPhone which has just connected to the Bangle. With the standard firmware, the widget reconnects to the iPhone as a Client - however this has greatly degraded performance. See [Issue 1800.](https://github.com/espruino/Espruino/issues/1800) for more details. + +2. When the Bangle switches apps, all state - including widget state - is lost unless explicitly stored. The consequence of this is that when the Bangle switches apps, the connection to iPhone has to be re-established to restore the remote GATT server and characteristics state. This is quite slow. To minimise reconnection, the widget needs to grab the screen from the running app to signal messages and calls. To allow this to work, the app needs to implement the `SCREENACCESS` interface. In essence, the widget only connects when running with compatible apps that implement this interface. An example implementation is: + +``` +var SCREENACCESS = { + withApp:true, + request:function(){ + this.withApp=false; + stopdraw(); //clears redraw timers etc + clearWatch(); //clears button handlers + }, + release:function(){ + this.withApp=true; + startdraw(); //redraw app screen, restart timers etc + setButtons(); //install button event handlers + } +} + +Bangle.on('lcdPower',function(on) { + if (!SCREENACCESS.withApp) return; + if (on) { + startdraw(); + } else { + stopdraw(); + } +}); +``` + +## Support + +Please report bugs etc. by raising an issue [here](https://github.com/jeffmer/JeffsBangleAppsDev). \ No newline at end of file diff --git a/apps/widancs/ancs.js b/apps/widancs/ancs.js new file mode 100644 index 000000000..84a79fbf9 --- /dev/null +++ b/apps/widancs/ancs.js @@ -0,0 +1,264 @@ +(() => { + + var s = require("Storage").readJSON("widancs.json",1)||{settings:{enabled:false, category:[1,2,4]}}; + var ENABLED = s.settings.enabled; + var CATEGORY = s.settings.category; + + function advert(){ + NRF.setAdvertising([ + 0x02, //length + 0x01, //flags + 0x06, // + 0x11, //length + 0x15, //solicited Service UUID + 0xD0,0x00,0x2D,0x12,0x1E,0x4B, + 0x0F,0xA4, + 0x99,0x4E, + 0xCE,0xB5, + 0x31,0xF4,0x05,0x79],{connectable:true,discoverable:true,interval:375}); + } + + var state = { + gatt:null, + ancs:null, + current:{cat:0,uid:0}, + notqueue:[], + msgTO:undefined, + com:new Uint8Array([0,0,0,0,0,1,20,0,3,100,0]), + buf:new Uint8Array(132), + inp:0, + store:function(b){ + var i = this.inp; + if (i+b.length<=132){ + this.buf.set(b,i); + this.inp+=b.length; + } + }, + gotmsg:function(){ + var n = this.inp; + var vw = DataView(this.buf.buffer); + if (n<8) return null; + var tn=vw.getUint16(6,true); + if (n<(tn+8)) return null; + var mn=vw.getUint16(9+tn,true); + if (n<(mn+tn+11)) return null; + return {tlen:tn, mlen:mn}; + } + }; + + //stop advertising when peripheral link disconnected + if (!NRF.getGattforCentralServer && ENABLED && typeof SCREENACCESS!='undefined') + NRF.on('disconnect',function(reason){ + NRF.sleep(); + }); + + if (ENABLED && typeof SCREENACCESS!='undefined') + NRF.on('connect',function(addr){ + if(NRF.getGattforCentralServer) + do_bond(NRF.getGattforCentralServer(addr)); + else + NRF.connect(addr).then(do_bond); + }); + + function do_bond(g) { + var tval, ival; + state.gatt = g; + function cleanup(){ + drawIcon(0); //disconnect from iPhone + delete state.gatt; + delete state.ancs; + if(!NRF.getGattforCentralServer) NRF.disconnect(); + setTimeout(()=>{NRF.wake();},500); + } + drawIcon(1); //connect from iPhone + state.gatt.device.on('gattserverdisconnected', function(reason) { + if (ival) clearInterval(ival); + if (tval) clearInterval(tval); + cleanup(); + }); + E.on("kill",function(){ + state.gatt.disconnect().then(function(){NRF.sleep();}); + }); + NRF.setSecurity({passkey:"123456",mitm:1,display:1}); + tval = setTimeout(function(){ + if (ival) clearInterval(ival); + state.gatt.disconnect().then(cleanup); + },10000); + state.gatt.startBonding().then(function(){ + ival = setInterval(function(){ + var sec = state.gatt.getSecurityStatus(); + if (!sec.connected) {clearInterval(ival); clearTimeout(tval); return;} + if (sec.connected && sec.encrypted){ + clearInterval(ival); + clearTimeout(tval); + drawIcon(2); //bonded to iPhone + do_ancs(); + return; + } + },1000); + }).catch(function(e){ + Terminal.println("ERROR "+e); + }); + } + + function do_ancs() { + state.ancs = {primary:null, notify:null, control:null, data:null}; + state.gatt.getPrimaryService("7905F431-B5CE-4E99-A40F-4B1E122D00D0").then(function(s) { + state.ancs.primary=s; + return s.getCharacteristic("9FBF120D-6301-42D9-8C58-25E699A21DBD"); + }).then(function(c) { + state.ancs.notify=c; + return state.ancs.primary.getCharacteristic("69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9"); + }).then(function(c) { + state.ancs.control=c; + return state.ancs.primary.getCharacteristic("22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB"); + }).then(function(c) { + state.ancs.data =c; + drawIcon(3);//got remote services + state.ancs.notify.on('characteristicvaluechanged', function(ev) { + getnotify(ev.target.value); + }); + state.ancs.data.on('characteristicvaluechanged', function(e) { + state.store(e.target.value.buffer); + var inds = state.gotmsg(); + if (inds) printmsg(state.buf,inds); + }); + state.ancs.notify.startNotifications().then(function(){ + state.ancs.data.startNotifications().then(function(){ + drawIcon(4); //ready for messages + }); + }); + }).catch(function(e){ + Terminal.println("ERROR "+e); + }); + } + + function wordwrap(s){ + var txt = s.split("\n"); + var MAXCHARS = 18; + for (var i = 0; i < txt.length; i++) { + txt[i] = txt[i].trim(); + var l = txt[i]; + if (l.length > MAXCHARS) { + var p = MAXCHARS; + while (p > MAXCHARS - 8 && !" \t-_".includes(l[p])) + p--; + if (p == MAXCHARS - 8) p = MAXCHARS; + txt[i] = l.substr(0, p); + txt.splice(i + 1, 0, l.substr(p)); + } + } + return txt.join("\n"); + } + + + var buzzing =false; + var screentimeout = undefined; + var inalert = false; + + function release_screen(){ + screentimeout= setTimeout(() => { + SCREENACCESS.release(); + screentimeout = undefined; + inalert=false; + next_notify(); + }, 500); + } + + function printmsg(buf,inds){ + + function send_action(tf){ + var bb = new Uint8Array(6); + var v = DataView(bb.buffer); + v.setUint8(0,2); + v.setUint32(1,state.current.uid,true); + v.setUint8(5,tf?0:1 ); + state.ancs.control.writeValue(bb).then(release_screen); + } + + if (state.msgTO) clearTimeout(state.msgTO); + var title=""; + for (var i=8;i<8+inds.tlen; ++i) title+=String.fromCharCode(buf[i]); + var message = ""; + for (var j=11+inds.tlen;j<11+inds.tlen+inds.mlen;++j) { + message+=String.fromCharCode(buf[j]); + } + message = wordwrap(message); + //we may already be displaying a prompt, so clear it + E.showPrompt(); + if (screentimeout) clearTimeout(screentimeout); + Bangle.setLCDPower(true); + SCREENACCESS.request(); + if (!buzzing){ + buzzing=true; + Bangle.buzz(500).then(()=>{buzzing=false;}); + } + if (state.current.cat!=1){ + E.showAlert(message,title).then(send_action.bind(null,false)); + } else { + E.showPrompt(message,{title:title,buttons:{"Accept":true,"Cancel":false}}).then(send_action); + } + } + + var notifyTO; + function getnotify(d){ + var eid = d.getUint8(0); + var ct = d.getUint8(2); + var id = d.getUint32(4,true); + if (eid>1) return; + if (notifyTO) clearTimeout(notifyTO); + if(!CATEGORY.includes(ct)) return; + var len = state.notqueue.length; + if (ct == 1) { // it's a call so pre-empt + if (inalert) {state.notqueue.push(state.current); inalert=false;} + state.notqueue.push({cat:ct, uid:id}); + } else if (len<16) + state.notqueue[len] = {cat:ct, uid:id}; + notifyTO = setTimeout(next_notify,1000); + } + + function next_notify(){ + if(state.notqueue.length==0 || inalert) return; + inalert=true; + state.current = state.notqueue.pop(); + var v = DataView(state.com.buffer); + if (state.current.cat==6) v.setUint8(8,2); else v.setUint8(8,3);//get email title + v.setUint32(1,state.current.uid,true); + state.inp=0; + state.ancs.control.writeValue(state.com).then(function(){ + state.msgTO=setTimeout(()=>{ + inalert=false; + state.msgTO=undefined; + next_notify(); + },1000); + }); + } + + var stage = 5; + //grey, pink, lightblue, yellow, green + function draw(){ + var colors = new Uint16Array([0xc618,0xf818,0x3ff,0xffe0,0x07e0,0x0000]); + var img = E.toArrayBuffer(atob("GBgBAAAABAAADgAAHwAAPwAAf4AAP4AAP4AAP4AAHwAAH4AAD8AAB+AAA/AAAfgAAf3gAH/4AD/8AB/+AA/8AAf4AAHwAAAgAAAA")); + g.setColor(colors[stage]); + g.drawImage(img,this.x,this.y); + } + + WIDGETS["ancs"] ={area:"tl", width:24,draw:draw}; + + function drawIcon(id){ + stage = id; + WIDGETS["ancs"].draw(); + } + + if (ENABLED && typeof SCREENACCESS!='undefined') { + stage = 0; + NRF.setServices(undefined,{uart:false}); + NRF.sleep(); + NRF.wake(); + advert(); + } + + })(); + + + \ No newline at end of file diff --git a/apps/widancs/ancs.min.js b/apps/widancs/ancs.min.js new file mode 100644 index 000000000..8ccf58e61 --- /dev/null +++ b/apps/widancs/ancs.min.js @@ -0,0 +1,10 @@ +(function(){function t(a){function e(){k(0);delete b.gatt;delete b.ancs;NRF.getGattforCentralServer||NRF.disconnect();setTimeout(function(){NRF.wake()},500)}var d;b.gatt=a;k(1);b.gatt.device.on("gattserverdisconnected",function(a){d&&clearInterval(d);c&&clearInterval(c);e()});E.on("kill",function(){b.gatt.disconnect().then(function(){NRF.sleep()})});NRF.setSecurity({passkey:"123456",mitm:1,display:1});var c=setTimeout(function(){d&&clearInterval(d);b.gatt.disconnect().then(e)},1E4);b.gatt.startBonding().then(function(){d= + setInterval(function(){var a=b.gatt.getSecurityStatus();a.connected?a.connected&&a.encrypted&&(clearInterval(d),clearTimeout(c),k(2),v()):(clearInterval(d),clearTimeout(c))},1E3)})["catch"](function(a){Terminal.println("ERROR "+a)})}function v(){b.ancs={primary:null,notify:null,control:null,data:null};b.gatt.getPrimaryService("7905F431-B5CE-4E99-A40F-4B1E122D00D0").then(function(a){b.ancs.primary=a;return a.getCharacteristic("9FBF120D-6301-42D9-8C58-25E699A21DBD")}).then(function(a){b.ancs.notify= + a;return b.ancs.primary.getCharacteristic("69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9")}).then(function(a){b.ancs.control=a;return b.ancs.primary.getCharacteristic("22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB")}).then(function(a){b.ancs.data=a;k(3);b.ancs.notify.on("characteristicvaluechanged",function(a){var e=a.target.value,c=e.getUint8(0);a=e.getUint8(2);e=e.getUint32(4,!0);1<c||(m&&clearTimeout(m),w.includes(a)&&(c=b.notqueue.length,1==a?(f&&(b.notqueue.push(b.current),f=!1),b.notqueue.push({cat:a,uid:e})): + 16>c&&(b.notqueue[c]={cat:a,uid:e}),m=setTimeout(n,1E3)))});b.ancs.data.on("characteristicvaluechanged",function(a){b.store(a.target.value.buffer);(a=b.gotmsg())&&x(b.buf,a)});b.ancs.notify.startNotifications().then(function(){b.ancs.data.startNotifications().then(function(){k(4)})})})["catch"](function(a){Terminal.println("ERROR "+a)})}function y(a){a=a.split("\n");for(var b=0;b<a.length;b++){a[b]=a[b].trim();var d=a[b];if(18<d.length){for(var c=18;10<c&&!" \t-_".includes(d[c]);)c--;10==c&&(c=18); + a[b]=d.substr(0,c);a.splice(b+1,0,d.substr(c))}}return a.join("\n")}function z(){l=setTimeout(function(){SCREENACCESS.release();l=void 0;f=!1;n()},500)}function x(a,e){function d(a){var e=new Uint8Array(6),c=DataView(e.buffer);c.setUint8(0,2);c.setUint32(1,b.current.uid,!0);c.setUint8(5,a?0:1);b.ancs.control.writeValue(e).then(z)}b.msgTO&&clearTimeout(b.msgTO);for(var c="",h=8;h<8+e.tlen;++h)c+=String.fromCharCode(a[h]);h="";for(var f=11+e.tlen;f<11+e.tlen+e.mlen;++f)h+=String.fromCharCode(a[f]); + h=y(h);E.showPrompt();l&&clearTimeout(l);Bangle.setLCDPower(!0);SCREENACCESS.request();p||(p=!0,Bangle.buzz(500).then(function(){p=!1}));1!=b.current.cat?E.showAlert(h,c).then(d.bind(null,!1)):E.showPrompt(h,{title:c,buttons:{Accept:!0,Cancel:!1}}).then(d)}function n(){if(0!=b.notqueue.length&&!f){f=!0;b.current=b.notqueue.pop();var a=DataView(b.com.buffer);6==b.current.cat?a.setUint8(8,2):a.setUint8(8,3);a.setUint32(1,b.current.uid,!0);b.inp=0;b.ancs.control.writeValue(b.com).then(function(){b.msgTO= + setTimeout(function(){f=!1;b.msgTO=void 0;n()},1E3)})}}function k(a){q=a;WIDGETS.ancs.draw()}var u=require("Storage").readJSON("widancs.json",1)||{settings:{enabled:!1,category:[1,2,4]}},r=u.settings.enabled,w=u.settings.category,b={gatt:null,ancs:null,current:{cat:0,uid:0},notqueue:[],msgTO:void 0,com:new Uint8Array([0,0,0,0,0,1,20,0,3,100,0]),buf:new Uint8Array(132),inp:0,store:function(a){var b=this.inp;132>=b+a.length&&(this.buf.set(a,b),this.inp+=a.length)},gotmsg:function(){var a=this.inp,b= + DataView(this.buf.buffer);if(8>a)return null;var d=b.getUint16(6,!0);if(a<d+8)return null;b=b.getUint16(9+d,!0);return a<b+d+11?null:{tlen:d,mlen:b}}};if(!NRF.getGattforCentralServer&&r&&"undefined"!=typeof SCREENACCESS)NRF.on("disconnect",function(a){NRF.sleep()});if(r&&"undefined"!=typeof SCREENACCESS)NRF.on("connect",function(a){NRF.getGattforCentralServer?t(NRF.getGattforCentralServer(a)):NRF.connect(a).then(t)});var p=!1,l=void 0,f=!1,m,q=5;WIDGETS.ancs={area:"tl",width:24,draw:function(){var a= + new Uint16Array([50712,63512,1023,65504,2016,0]),b=E.toArrayBuffer(atob("GBgBAAAABAAADgAAHwAAPwAAf4AAP4AAP4AAP4AAHwAAH4AAD8AAB+AAA/AAAfgAAf3gAH/4AD/8AB/+AA/8AAf4AAHwAAAgAAAA"));g.setColor(a[q]);g.drawImage(b,this.x,this.y)}};r&&"undefined"!=typeof SCREENACCESS&&(q=0,NRF.setServices(void 0,{uart:!1}),NRF.sleep(),NRF.wake(),NRF.setAdvertising([2,1,6,17,21,208,0,45,18,30,75,15,164,153,78,206,181,49,244,5,121],{connectable:!0,discoverable:!0,interval:375}))})(); + \ No newline at end of file diff --git a/apps/widancs/call_pic.jpg b/apps/widancs/call_pic.jpg new file mode 100644 index 000000000..2fdc21e33 Binary files /dev/null and b/apps/widancs/call_pic.jpg differ diff --git a/apps/widancs/message_pic.jpg b/apps/widancs/message_pic.jpg new file mode 100644 index 000000000..43fa66023 Binary files /dev/null and b/apps/widancs/message_pic.jpg differ diff --git a/apps/widancs/missed_pic.jpg b/apps/widancs/missed_pic.jpg new file mode 100644 index 000000000..c9d958ec6 Binary files /dev/null and b/apps/widancs/missed_pic.jpg differ diff --git a/apps/widancs/settings.js b/apps/widancs/settings.js new file mode 100644 index 000000000..8964d560c --- /dev/null +++ b/apps/widancs/settings.js @@ -0,0 +1,61 @@ +(function(back) { + const ANCSFILE = "widancs.json"; + + // initialize with default settings... + let s = { + 'enabled': false, + 'category':[1,2,4] + }; + // ...and overwrite them with any saved values + // This way saved values are preserved if a new version adds more settings + const storage = require('Storage'); + const d = storage.readJSON(ANCSFILE, 1) || {}; + const saved = d.settings || {}; + for (const key in saved) { + s[key] = saved[key]; + } + + function save() { + d.settings = s; + storage.write(ANCSFILE, d); + } + + function setcategory(){ + const names = ["Other","Call ","Missed Call","Voicemail","Messages ","Calendar","Email","News ","Fitness ","Busniness","Location ","Entertainment"]; + function hascat(n){return s.category.includes(n);} + function setcat(n,v){ + if (v) + s.category.push(n); + else + s.category = s.category.filter((v,i,a)=>{return v!=n;}); + } + const menu = { + '': { 'title': 'Set Categories' } + }; + for (var i=0; i<names.length;++i) + menu[names[i]]={ + value:hascat(i), + format:v=>v?'Yes':'No', + onchange:setcat.bind(null,i) + }; + menu['< Back'] = ()=>{save(); showMain();}; + return E.showMenu(menu); + } + + function showMain(){ + return E.showMenu({ + 'Enable ANCS': { + value: s.enabled, + format: () => (s.enabled ? 'Yes' : 'No'), + onchange: () => { + s.enabled = !s.enabled; + save(); + }, + }, + 'Set Category':setcategory, + '< Back': back, + }); + } + + showMain(); +}); \ No newline at end of file diff --git a/apps/widancs/widget.png b/apps/widancs/widget.png new file mode 100644 index 000000000..c6f57cc1e Binary files /dev/null and b/apps/widancs/widget.png differ diff --git a/apps/widancs/widget_pic.jpg b/apps/widancs/widget_pic.jpg new file mode 100644 index 000000000..68b04f2e9 Binary files /dev/null and b/apps/widancs/widget_pic.jpg differ diff --git a/apps/widbat/widget.js b/apps/widbat/widget.js index dd6774d4c..bca3ae046 100644 --- a/apps/widbat/widget.js +++ b/apps/widbat/widget.js @@ -1,43 +1,43 @@ (function(){ -var CHARGING = 0x07E0; + var CHARGING = 0x07E0; -function setWidth() { - WIDGETS["bat"].width = 40 + (Bangle.isCharging()?16:0); -} -function draw() { - var s = 39; - var x = this.x, y = this.y; - if (Bangle.isCharging()) { - g.setColor(CHARGING).drawImage(atob("DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg"),x,y); - x+=16; + function setWidth() { + WIDGETS["bat"].width = 40 + (Bangle.isCharging()?16:0); } - g.setColor(-1); - g.fillRect(x,y+2,x+s-4,y+21); - g.clearRect(x+2,y+4,x+s-6,y+19); - g.fillRect(x+s-3,y+10,x+s,y+14); - g.setColor(CHARGING).fillRect(x+4,y+6,x+4+E.getBattery()*(s-12)/100,y+17); - g.setColor(-1); -} -Bangle.on('charging',function(charging) { - if(charging) Bangle.buzz(); + function draw() { + var s = 39; + var x = this.x, y = this.y; + if (Bangle.isCharging()) { + g.setColor(CHARGING).drawImage(atob("DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg"),x,y); + x+=16; + } + g.setColor(-1); + g.fillRect(x,y+2,x+s-4,y+21); + g.clearRect(x+2,y+4,x+s-6,y+19); + g.fillRect(x+s-3,y+10,x+s,y+14); + g.setColor(CHARGING).fillRect(x+4,y+6,x+4+E.getBattery()*(s-12)/100,y+17); + g.setColor(-1); + } + Bangle.on('charging',function(charging) { + if(charging) Bangle.buzz(); + setWidth(); + Bangle.drawWidgets(); // relayout widgets + g.flip(); + }); + var batteryInterval; + Bangle.on('lcdPower', function(on) { + if (on) { + WIDGETS["bat"].draw(); + // refresh once a minute if LCD on + if (!batteryInterval) + batteryInterval = setInterval(()=>WIDGETS["bat"].draw(), 60000); + } else { + if (batteryInterval) { + clearInterval(batteryInterval); + batteryInterval = undefined; + } + } + }); + WIDGETS["bat"]={area:"tr",width:40,draw:draw}; setWidth(); - Bangle.drawWidgets(); // relayout widgets - g.flip(); -}); -var batteryInterval; -Bangle.on('lcdPower', function(on) { - if (on) { - WIDGETS["bat"].draw(); - // refresh once a minute if LCD on - if (!batteryInterval) - batteryInterval = setInterval(()=>WIDGETS["bat"].draw(), 60000); - } else { - if (batteryInterval) { - clearInterval(batteryInterval); - batteryInterval = undefined; - } - } -}); -WIDGETS["bat"]={area:"tr",width:40,draw:draw}; -setWidth(); })() diff --git a/apps/widbatpc/ChangeLog b/apps/widbatpc/ChangeLog index 129707320..a8851b1d8 100644 --- a/apps/widbatpc/ChangeLog +++ b/apps/widbatpc/ChangeLog @@ -6,3 +6,5 @@ 0.07: Add settings: percentage/color/charger icon 0.08: Draw percentage as inverted on monochrome battery 0.09: Fix regression stopping correct widget updates +0.10: Add 'hide if charge greater than' +0.11: Don't overwrite existing settings on app update diff --git a/apps/widbatpc/settings.js b/apps/widbatpc/settings.js index 5c0bdbcae..009fa4994 100644 --- a/apps/widbatpc/settings.js +++ b/apps/widbatpc/settings.js @@ -3,7 +3,7 @@ * @param {function} back Use back() to return to settings menu */ (function(back) { - const SETTINGS_FILE = 'widbatpc.settings.json' + const SETTINGS_FILE = 'widbatpc.json' const COLORS = ['By Level', 'Green', 'Monochrome'] // initialize with default settings... @@ -11,21 +11,22 @@ 'color': COLORS[0], 'percentage': true, 'charger': true, + 'hideifmorethan': 100, } // ...and overwrite them with any saved values // This way saved values are preserved if a new version adds more settings const storage = require('Storage') const saved = storage.readJSON(SETTINGS_FILE, 1) || {} for (const key in saved) { - s[key] = saved[key] + s[key] = saved[key]; } // creates a function to safe a specific setting, e.g. save('color')(1) function save(key) { return function (value) { - s[key] = value - storage.write(SETTINGS_FILE, s) - WIDGETS["batpc"].reload() + s[key] = value; + storage.write(SETTINGS_FILE, s); + WIDGETS["batpc"].reload(); } } @@ -51,7 +52,15 @@ const newIndex = (oldIndex + 1) % COLORS.length s.color = COLORS[newIndex] save('color')(s.color) - }, + } + }, + 'Hide if >': { + value: s.hideifmorethan||100, + min: 10, + max : 100, + step: 10, + format: x => x+"%", + onchange: save('hideifmorethan'), }, } E.showMenu(menu) diff --git a/apps/widbatpc/widget.js b/apps/widbatpc/widget.js index aca690ce0..9bf43cfaa 100644 --- a/apps/widbatpc/widget.js +++ b/apps/widbatpc/widget.js @@ -1,123 +1,140 @@ (function(){ -const DEFAULTS = { - 'color': 'By Level', - 'percentage': true, - 'charger': true, -} -const COLORS = { - 'white': -1, - 'charging': 0x07E0, // "Green" - 'high': 0x05E0, // slightly darker green - 'ok': 0xFD20, // "Orange" - 'low':0xF800, // "Red" -} -const SETTINGS_FILE = 'widbatpc.settings.json' + const COLORS = { + 'white': -1, + 'charging': 0x07E0, // "Green" + 'high': 0x05E0, // slightly darker green + 'ok': 0xFD20, // "Orange" + 'low':0xF800, // "Red" + } + const SETTINGS_FILE = 'widbatpc.json' -let settings -function loadSettings() { - settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {} -} -function setting(key) { - if (!settings) { loadSettings() } - return (key in settings) ? settings[key] : DEFAULTS[key] -} + let settings + function loadSettings() { + settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {} + const DEFAULTS = { + 'color': 'By Level', + 'percentage': true, + 'charger': true, + 'hideifmorethan': 100, + }; + Object.keys(DEFAULTS).forEach(k=>{ + if (settings[k]===undefined) settings[k]=DEFAULTS[k] + }); + } + function setting(key) { + if (!settings) { loadSettings() } + return settings[key]; + } -const levelColor = (l) => { + const levelColor = (l) => { // "charging" is very bright -> percentage is hard to read, "high" is ok(ish) - const green = setting('percentage') ? COLORS.high : COLORS.charging - switch (setting('color')) { - case 'Monochrome': return COLORS.white; // no chance of reading the percentage here :-( - case 'Green': return green; - case 'By Level': // fall through - default: - if (setting('charger')) { + const green = setting('percentage') ? COLORS.high : COLORS.charging + switch (setting('color')) { + case 'Monochrome': return COLORS.white; // no chance of reading the percentage here :-( + case 'Green': return green; + case 'By Level': // fall through + default: + if (setting('charger')) { // charger icon -> always make percentage readable - if (Bangle.isCharging() || l >= 50) return green; - } else { + if (Bangle.isCharging() || l >= 50) return green; + } else { // no icon -> brightest green to indicate charging, even when showing percentage - if (Bangle.isCharging()) return COLORS.charging; - if (l >= 50) return COLORS.high; - } - if (l >= 15) return COLORS.ok; - return COLORS.low; + if (Bangle.isCharging()) return COLORS.charging; + if (l >= 50) return COLORS.high; + } + if (l >= 15) return COLORS.ok; + return COLORS.low; + } } -} -const chargerColor = () => { - return (setting('color') === 'Monochrome') ? COLORS.white : COLORS.charging -} + const chargerColor = () => { + return (setting('color') === 'Monochrome') ? COLORS.white : COLORS.charging + } + // sets width, returns true if it changed + function setWidth() { + var w = 40; + if (Bangle.isCharging() && setting('charger')) + w += 16; + if (E.getBattery() > setting('hideifmorethan')) + w = 0; + var changed = WIDGETS["batpc"].width != w; + WIDGETS["batpc"].width = w; + return changed; + } + function draw() { + // if hidden, don't draw + if (!WIDGETS["batpc"].width) return; + // else... + var s = 39; + var x = this.x, y = this.y; + const l = E.getBattery(), + c = levelColor(l); + const xl = x+4+l*(s-12)/100 -function setWidth() { - WIDGETS["batpc"].width = 40; - if (Bangle.isCharging() && setting('charger')) { - WIDGETS["batpc"].width += 16; - } -} -function draw() { - var s = 39; - var x = this.x, y = this.y; - if (Bangle.isCharging() && setting('charger')) { - g.setColor(chargerColor()).drawImage(atob( - "DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg"),x,y); - x+=16; - } - g.setColor(-1); - g.fillRect(x,y+2,x+s-4,y+21); - g.clearRect(x+2,y+4,x+s-6,y+19); - g.fillRect(x+s-3,y+10,x+s,y+14); - const l = E.getBattery(), - c = levelColor(l); - const xl = x+4+l*(s-12)/100 - g.setColor(c).fillRect(x+4,y+6,xl,y+17); - g.setColor(-1); - if (!setting('percentage')) { - return; - } - let gfx = g - if (setting('color') === 'Monochrome') { + if (Bangle.isCharging() && setting('charger')) { + g.setColor(chargerColor()).drawImage(atob( + "DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg"),x,y); + x+=16; + } + g.setColor(-1); + g.fillRect(x,y+2,x+s-4,y+21); + g.clearRect(x+2,y+4,x+s-6,y+19); + g.fillRect(x+s-3,y+10,x+s,y+14); + + g.setColor(c).fillRect(x+4,y+6,xl,y+17); + g.setColor(-1); + if (!setting('percentage')) { + return; + } + let gfx = g + if (setting('color') === 'Monochrome') { // draw text inverted on battery level - gfx = Graphics.createCallback(240, 240, 1, - (x,y) => {g.setPixel(x,y,x<=xl?0:-1)}) + gfx = Graphics.createCallback(240, 240, 1, + (x,y) => {g.setPixel(x,y,x<=xl?0:-1)}) + } + gfx.setFontAlign(-1,-1); + if (l >= 100) { + gfx.setFont('4x6', 2); + gfx.drawString(l, x + 6, y + 7); + } else { + if (l < 10) x+=6; + gfx.setFont('6x8', 2); + gfx.drawString(l, x + 6, y + 4); + } } - gfx.setFontAlign(-1,-1); - if (l >= 100) { - gfx.setFont('4x6', 2); - gfx.drawString(l, x + 6, y + 7); - } else { - if (l < 10) x+=6; - gfx.setFont('6x8', 2); - gfx.drawString(l, x + 6, y + 4); + // reload widget, e.g. when settings have changed + function reload() { + loadSettings() + // need to redraw all widgets, because changing the "charger" setting + // can affect the width and mess with the whole widget layout + setWidth() + g.clear(); + Bangle.drawWidgets(); + } + // update widget - redraw just widget, or all widgets if size changed + function update() { + if (setWidth()) Bangle.drawWidgets(); + else WIDGETS["batpc"].draw(); } -} -// reload widget, e.g. when settings have changed -function reload() { - loadSettings() - // need to redraw all widgets, because changing the "charger" setting - // can affect the width and mess with the whole widget layout - setWidth() - g.clear(); - Bangle.drawWidgets(); -} -Bangle.on('charging',function(charging) { - if(charging) Bangle.buzz(); + Bangle.on('charging',function(charging) { + if(charging) Bangle.buzz(); + update(); + g.flip(); + }); + var batteryInterval; + Bangle.on('lcdPower', function(on) { + if (on) { + update(); + // refresh once a minute if LCD on + if (!batteryInterval) + batteryInterval = setInterval(update, 60000); + } else { + if (batteryInterval) { + clearInterval(batteryInterval); + batteryInterval = undefined; + } + } + }); + WIDGETS["batpc"]={area:"tr",width:40,draw:draw,reload:reload}; setWidth(); - Bangle.drawWidgets(); // relayout widgets - g.flip(); -}); -var batteryInterval; -Bangle.on('lcdPower', function(on) { - if (on) { - WIDGETS["batpc"].draw(); - // refresh once a minute if LCD on - if (!batteryInterval) - batteryInterval = setInterval(()=>WIDGETS["batpc"].draw(), 60000); - } else { - if (batteryInterval) { - clearInterval(batteryInterval); - batteryInterval = undefined; - } - } -}); -WIDGETS["batpc"]={area:"tr",width:40,draw:draw,reload:reload}; -setWidth(); })() diff --git a/apps/widbatwarn/ChangeLog b/apps/widbatwarn/ChangeLog new file mode 100644 index 000000000..c51b06842 --- /dev/null +++ b/apps/widbatwarn/ChangeLog @@ -0,0 +1 @@ +0.01: New Battery Warning! \ No newline at end of file diff --git a/apps/widbatwarn/README.md b/apps/widbatwarn/README.md new file mode 100644 index 000000000..28b9bf550 --- /dev/null +++ b/apps/widbatwarn/README.md @@ -0,0 +1,14 @@ +# Battery Warning + +Get a notification when your battery runs low. + +![Screenshot](screenshot.png) + +## Settings: + +* Percentage: Warn when battery reaches this level +* Buzz: Enable/disable buzzer + +## Creator + +Richard de Boer <rigrig+banglejs@tubul.net> diff --git a/apps/widbatwarn/battery-low.png b/apps/widbatwarn/battery-low.png new file mode 100644 index 000000000..0955a0578 Binary files /dev/null and b/apps/widbatwarn/battery-low.png differ diff --git a/apps/widbatwarn/icons.txt b/apps/widbatwarn/icons.txt new file mode 100644 index 000000000..2e8dba984 --- /dev/null +++ b/apps/widbatwarn/icons.txt @@ -0,0 +1,2 @@ +widget.png: https://icons8.com/icon/vga9edYpuB7a/warning-battery +battery-low.png: https://icons8.com/icon/96282/low-battery (recolored) \ No newline at end of file diff --git a/apps/widbatwarn/screenshot.png b/apps/widbatwarn/screenshot.png new file mode 100644 index 000000000..30c23f050 Binary files /dev/null and b/apps/widbatwarn/screenshot.png differ diff --git a/apps/widbatwarn/settings.js b/apps/widbatwarn/settings.js new file mode 100644 index 000000000..8d15c8458 --- /dev/null +++ b/apps/widbatwarn/settings.js @@ -0,0 +1,47 @@ +/** + * @param {function} back Use back() to return to settings menu + */ +(function(back) { + const SETTINGS_FILE = "widbatwarn.json", + storage = require("Storage"), + translate = require("locale").translate; + + // initialize with default settings... + let s = { + buzz: true, + percentage: 10, + }; + // ...and overwrite them with any saved values + // This way saved values are preserved if a new version adds more settings + const saved = storage.readJSON(SETTINGS_FILE, 1) || {}; + for(const key in saved) { + s[key] = saved[key]; + } + + // creates a function to safe a specific setting, e.g. save('buzz')(true) + function save(key) { + return function(value) { + s[key] = value; + storage.write(SETTINGS_FILE, s); + WIDGETS["batwarn"].reload(); + }; + } + + const menu = { + "": {"title": "Battery Warning"}, + "< Back": back, + "Percentage": { + value: s.percentage, + min: 5, + max: 100, + step: 5, + onchange: save("percentage"), + }, + "Buzz": { + value: s.buzz, + format: b => translate(b?"Yes":"No"), + onchange: save("buzz"), + }, + }; + E.showMenu(menu); +}); \ No newline at end of file diff --git a/apps/widbatwarn/widget.js b/apps/widbatwarn/widget.js new file mode 100644 index 000000000..c5c2f2bf0 --- /dev/null +++ b/apps/widbatwarn/widget.js @@ -0,0 +1,59 @@ +(function() { + const SETTINGS_FILE = "widbatwarn.json"; + let settings; + + function loadSettings() { + settings = require("Storage").readJSON(SETTINGS_FILE, 1) || {}; + const DEFAULTS = { + buzz: true, + percentage: 10, + }; + Object.keys(DEFAULTS).forEach(k => { + if (settings[k]===undefined) settings[k] = DEFAULTS[k]; + }); + } + + function setting(key) { + if (!settings) { loadSettings(); } + return settings[key]; + } + + let warning = false; // did we show the warning already? + function check() { + if (Bangle.isCharging() + || E.getBattery()>setting("percentage")) { + require("notify").hide({id: "widbatwarn"}); + warning = false; + return; + } + if (warning) return; // already warned + warning = true; // only show once (until we recharge) + require("notify").show({ + size: 56, id: "widbatwarn", + // battery-low.png + icon: require("heatshrink").decompress(atob("jEYwgfchnM5nABaQJCBoQLSAhAL/Bf6bHAAYLpACgA==")), + title: "Low Battery", + render: a => { + g.setFont("6x8", 2).setFontAlign(-1, 0) + .setColor(-1).drawString("Battery: ", a.x+8, a.y+a.h/2) + .setColor(0xF800).drawString(`${E.getBattery()}%`, a.x+8+100, a.y+a.h/2); + }, + }); + if (setting("buzz")) Bangle.buzz(); + } + + Bangle.on("charging", check); + + function reload() { + loadSettings(); + // check right away, so user sees it work when fiddling with settings + check(); + } + + // we never draw anything, but 'area' and 'draw' are required + WIDGETS["batwarn"] = {width: 0, reload: reload, area: "tl", draw: () => {}}; + + // check every minute + // deliberately not right away, to prevent instant notifications in settings + setTimeout(check, 60000); +})(); \ No newline at end of file diff --git a/apps/widbatwarn/widget.png b/apps/widbatwarn/widget.png new file mode 100644 index 000000000..8a3031ee1 Binary files /dev/null and b/apps/widbatwarn/widget.png differ diff --git a/apps/widbt/widget.js b/apps/widbt/widget.js index c3254c791..2236ee50d 100644 --- a/apps/widbt/widget.js +++ b/apps/widbt/widget.js @@ -1,19 +1,19 @@ (function(){ -var img_bt = E.toArrayBuffer(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA==")); + var img_bt = E.toArrayBuffer(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA==")); -function draw() { - g.reset(); - if (NRF.getSecurityStatus().connected) - g.setColor(0,0.5,1); - else - g.setColor(0.3,0.3,0.3); - g.drawImage(img_bt,10+this.x,2+this.y); -} -function changed() { - WIDGETS["bluetooth"].draw(); - g.flip();// turns screen on -} -NRF.on('connect',changed); -NRF.on('disconnect',changed); -WIDGETS["bluetooth"]={area:"tr",width:24,draw:draw}; + function draw() { + g.reset(); + if (NRF.getSecurityStatus().connected) + g.setColor(0,0.5,1); + else + g.setColor(0.3,0.3,0.3); + g.drawImage(img_bt,10+this.x,2+this.y); + } + function changed() { + WIDGETS["bluetooth"].draw(); + g.flip();// turns screen on + } + NRF.on('connect',changed); + NRF.on('disconnect',changed); + WIDGETS["bluetooth"]={area:"tr",width:24,draw:draw}; })() diff --git a/apps/widclk/widget.js b/apps/widclk/widget.js index ff22bb4d1..90280139e 100644 --- a/apps/widclk/widget.js +++ b/apps/widclk/widget.js @@ -1,27 +1,27 @@ (() => { - let intervalRef = null; - var width = 5 * 6*2 + let intervalRef = null; + var width = 5 * 6*2 - function draw() { - g.reset().setFont("6x8", 2).setFontAlign(-1, 0); - var time = require("locale").time(new Date(),1); - g.drawString(time, this.x, this.y+11, true); // 5 * 6*2 = 60 + function draw() { + g.reset().setFont("6x8", 2).setFontAlign(-1, 0); + var time = require("locale").time(new Date(),1); + g.drawString(time, this.x, this.y+11, true); // 5 * 6*2 = 60 + } + function clearTimers(){ + if(intervalRef) { + clearInterval(intervalRef); + intervalRef = null; } - function clearTimers(){ - if(intervalRef) { - clearInterval(intervalRef); - intervalRef = null; - } - } - function startTimers(){ - intervalRef = setInterval(()=>WIDGETS["wdclk"].draw(), 60*1000); - WIDGETS["wdclk"].draw(); - } - Bangle.on('lcdPower', (on) => { - clearTimers(); - if (on) startTimers(); - }); + } + function startTimers(){ + intervalRef = setInterval(()=>WIDGETS["wdclk"].draw(), 60*1000); + WIDGETS["wdclk"].draw(); + } + Bangle.on('lcdPower', (on) => { + clearTimers(); + if (on) startTimers(); + }); - WIDGETS["wdclk"]={area:"tr",width:width,draw:draw}; - if (Bangle.isLCDOn) intervalRef = setInterval(()=>WIDGETS["wdclk"].draw(), 60*1000); + WIDGETS["wdclk"]={area:"tr",width:width,draw:draw}; + if (Bangle.isLCDOn) intervalRef = setInterval(()=>WIDGETS["wdclk"].draw(), 60*1000); })() diff --git a/apps/widhrm/widget.js b/apps/widhrm/widget.js index ca66f8b44..a591fa0df 100644 --- a/apps/widhrm/widget.js +++ b/apps/widhrm/widget.js @@ -5,7 +5,7 @@ function draw() { var width = 24; - g.reset(); + g.reset(); g.setFont("6x8", 1); g.setFontAlign(0, 0); g.clearRect(this.x,this.y+15,this.x+width,this.y+23); // erase background diff --git a/apps/widhwt/widget.js b/apps/widhwt/widget.js index 3fff48800..6affdea52 100644 --- a/apps/widhwt/widget.js +++ b/apps/widhwt/widget.js @@ -1,23 +1,23 @@ /* jshint esversion: 6 */ (() => { - var icon = require("heatshrink").decompress(atob("jEYwIKHgwCBhwCBh4CEggPCkACBmAXDBwVZ+EB+F4gEsjl8EgMP+EChk/gEMh+ehkA+YIBxwxBnF/4HggH/wEAj0AA==")); - var color = 0x4A69; + var icon = require("heatshrink").decompress(atob("jEYwIKHgwCBhwCBh4CEggPCkACBmAXDBwVZ+EB+F4gEsjl8EgMP+EChk/gEMh+ehkA+YIBxwxBnF/4HggH/wEAj0AA==")); + var color = 0x4A69; - function draw() { - g.reset().setColor(color).drawImage(icon, this.x + 1, 0); - } + function draw() { + g.reset().setColor(color).drawImage(icon, this.x + 1, 0); + } - WIDGETS["widhwt"] = { area: "tr", width: 26, draw: draw }; + WIDGETS["widhwt"] = { area: "tr", width: 26, draw: draw }; - Bangle.on('swipe', function() { - color = 0x41f; - Bangle.buzz(); - Bangle.drawWidgets(); - setTimeout(() => { - color = 0x4A69; - Bangle.buzz(1E3, 1); - Bangle.drawWidgets(); - }, 35E3); + Bangle.on('swipe', function() { + color = 0x41f; + Bangle.buzz(); + Bangle.drawWidgets(); + setTimeout(() => { + color = 0x4A69; + Bangle.buzz(1E3, 1); + Bangle.drawWidgets(); + }, 35E3); - }); + }); })(); \ No newline at end of file diff --git a/apps/widid/widget.js b/apps/widid/widget.js index efbfdfd19..e97eecb65 100644 --- a/apps/widid/widget.js +++ b/apps/widid/widget.js @@ -1,12 +1,12 @@ /* jshint esversion: 6 */ (() => { - var id = NRF.getAddress().substr().substr(12).split(":"); + var id = NRF.getAddress().substr().substr(12).split(":"); - // draw your widget at xpos - function draw() { - g.reset().setColor(0, 0.5, 1).setFont("6x8", 1); - g.drawString(id[0], this.x+2, this.y+4, true); - g.drawString(id[1], this.x+2, this.y+14, true); - } - WIDGETS["widid"] = { area:"tr", width:16, draw: draw }; + // draw your widget at xpos + function draw() { + g.reset().setColor(0, 0.5, 1).setFont("6x8", 1); + g.drawString(id[0], this.x+2, this.y+4, true); + g.drawString(id[1], this.x+2, this.y+14, true); + } + WIDGETS["widid"] = { area:"tr", width:16, draw: draw }; })(); diff --git a/apps/widmp/widget.js b/apps/widmp/widget.js index be4c2bb39..cebdb60f5 100644 --- a/apps/widmp/widget.js +++ b/apps/widmp/widget.js @@ -1,33 +1,33 @@ /* jshint esversion: 6 */ (() => { - const BLACK = 0, MOON = 0x41f, MC = 29.5305882, NM = 694039.09; - var r = 12, mx = 0, my = 0; + const BLACK = 0, MOON = 0x41f, MC = 29.5305882, NM = 694039.09; + var r = 12, mx = 0, my = 0; - var moon = { - 0: () => { g.reset().setColor(BLACK).fillRect(mx - r, my - r, mx + r, my + r);}, - 1: () => { moon[0](); g.setColor(MOON).drawCircle(mx, my, r);}, - 2: () => { moon[3](); g.setColor(BLACK).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);}, - 3: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r).setColor(BLACK).fillRect(mx - r, my - r, mx, my + r);}, - 4: () => { moon[3](); g.setColor(MOON).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);}, - 5: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r);}, - 6: () => { moon[7](); g.setColor(MOON).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);}, - 7: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r).setColor(BLACK).fillRect(mx, my - r, mx + r + r, my + r);}, - 8: () => { moon[7](); g.setColor(BLACK).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);} - }; + var moon = { + 0: () => { g.reset().setColor(BLACK).fillRect(mx - r, my - r, mx + r, my + r);}, + 1: () => { moon[0](); g.setColor(MOON).drawCircle(mx, my, r);}, + 2: () => { moon[3](); g.setColor(BLACK).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);}, + 3: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r).setColor(BLACK).fillRect(mx - r, my - r, mx, my + r);}, + 4: () => { moon[3](); g.setColor(MOON).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);}, + 5: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r);}, + 6: () => { moon[7](); g.setColor(MOON).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);}, + 7: () => { moon[0](); g.setColor(MOON).fillCircle(mx, my, r).setColor(BLACK).fillRect(mx, my - r, mx + r + r, my + r);}, + 8: () => { moon[7](); g.setColor(BLACK).fillEllipse(mx - r / 2, my - r, mx + r / 2, my + r);} + }; - function moonPhase(d) { - var tmp, month = d.getMonth(), year = d.getFullYear(), day = d.getDate(); - if (month < 3) {year--; month += 12;} - tmp = ((365.25 * year + 30.6 * ++month + day - NM) / MC); - return Math.round(((tmp - (tmp | 0)) * 7)+1); - } + function moonPhase(d) { + var tmp, month = d.getMonth(), year = d.getFullYear(), day = d.getDate(); + if (month < 3) {year--; month += 12;} + tmp = ((365.25 * year + 30.6 * ++month + day - NM) / MC); + return Math.round(((tmp - (tmp | 0)) * 7)+1); + } - function draw() { - mx = this.x; my = this.y + 12; - moon[moonPhase(Date())](); - } + function draw() { + mx = this.x; my = this.y + 12; + moon[moonPhase(Date())](); + } - WIDGETS["widmoon"] = { area: "tr", width: 24, draw: draw }; + WIDGETS["widmoon"] = { area: "tr", width: 24, draw: draw }; })(); diff --git a/apps/widram/widget.js b/apps/widram/widget.js index 08710b726..dc7fed6c3 100644 --- a/apps/widram/widget.js +++ b/apps/widram/widget.js @@ -1,7 +1,7 @@ (() => { function draw() { g.reset(); - var m = process.memory(); + var m = process.memory(); var pc = Math.round(m.usage*100/m.total); g.drawImage(atob("BwgBqgP////AVQ=="), this.x+(24-7)/2, this.y+4); g.setColor(pc>70 ? "#ff0000" : (pc>50 ? "#ffff00" : "#ffffff")); @@ -10,14 +10,14 @@ var ramInterval; Bangle.on('lcdPower', function(on) { if (on) { - WIDGETS["ram"].draw(); - if (!ramInterval) ramInterval = setInterval(()=>WIDGETS["ram"].draw(), 10000); - } else { - if (ramInterval) { - clearInterval(ramInterval); - ramInterval = undefined; - } - } + WIDGETS["ram"].draw(); + if (!ramInterval) ramInterval = setInterval(()=>WIDGETS["ram"].draw(), 10000); + } else { + if (ramInterval) { + clearInterval(ramInterval); + ramInterval = undefined; + } + } }); WIDGETS["ram"]={area:"tl",width: 24,draw:draw}; })() diff --git a/apps/widtbat/widget.js b/apps/widtbat/widget.js index f60034300..8cc4b0c83 100644 --- a/apps/widtbat/widget.js +++ b/apps/widtbat/widget.js @@ -1,18 +1,18 @@ /* jshint esversion: 6 */ (() => { - const CBS = 0x41f, CBC = 0x07E0; - var batS = require("heatshrink").decompress(atob("j0TwIHEv///kD////EfAYPwuEAgPB4EAg/HCgMfzgDBvwOC/IOC84ONDoUcFgc/AYOAHYRDE")); - var xo = 6, xl = 22, yo = 9, h = 17; + const CBS = 0x41f, CBC = 0x07E0; + var batS = require("heatshrink").decompress(atob("j0TwIHEv///kD////EfAYPwuEAgPB4EAg/HCgMfzgDBvwOC/IOC84ONDoUcFgc/AYOAHYRDE")); + var xo = 6, xl = 22, yo = 9, h = 17; - function draw() { - g.reset().setColor(CBS).drawImage(batS, this.x + 1, this.y + 4); - g.setColor(0).fillRect(this.x + xo, this.y + yo, this.x + xl, this.y + h); - var cbc = (Bangle.isCharging()) ? CBC : CBS; - g.setColor(cbc).fillRect(this.x + xo, this.y + yo, this.x + (xl - xo) / 100 * E.getBattery() + xo, this.y + h); - } - Bangle.on('charging', function(charging) { - if (charging) Bangle.buzz(); - Bangle.drawWidgets(); - }); - WIDGETS["widtbat"] = { area:"tr", width:32, draw: draw }; + function draw() { + g.reset().setColor(CBS).drawImage(batS, this.x + 1, this.y + 4); + g.setColor(0).fillRect(this.x + xo, this.y + yo, this.x + xl, this.y + h); + var cbc = (Bangle.isCharging()) ? CBC : CBS; + g.setColor(cbc).fillRect(this.x + xo, this.y + yo, this.x + (xl - xo) / 100 * E.getBattery() + xo, this.y + h); + } + Bangle.on('charging', function(charging) { + if (charging) Bangle.buzz(); + Bangle.drawWidgets(); + }); + WIDGETS["widtbat"] = { area:"tr", width:32, draw: draw }; })(); diff --git a/apps/widver/widget.js b/apps/widver/widget.js index b5edfc08c..5da66444f 100644 --- a/apps/widver/widget.js +++ b/apps/widver/widget.js @@ -1,11 +1,11 @@ /* jshint esversion: 6 */ (() => { - var width = 28, - ver = process.env.VERSION.split('.'); - function draw() { - g.reset().setColor(0, 0.5, 1).setFont("6x8", 1); - g.drawString(ver[0], this.x + 2, this.y + 4, true); - g.setFontAlign(0, -1, 0).drawString(ver[1], this.x + width / 2, this.y + 14, true); - } - WIDGETS["version"] = { area: "tr", width: width, draw: draw }; + var width = 28, + ver = process.env.VERSION.split('.'); + function draw() { + g.reset().setColor(0, 0.5, 1).setFont("6x8", 1); + g.drawString(ver[0], this.x + 2, this.y + 4, true); + g.setFontAlign(0, -1, 0).drawString(ver[1], this.x + width / 2, this.y + 14, true); + } + WIDGETS["version"] = { area: "tr", width: width, draw: draw }; })(); diff --git a/apps/widviz/ChangeLog b/apps/widviz/ChangeLog new file mode 100644 index 000000000..e1958b429 --- /dev/null +++ b/apps/widviz/ChangeLog @@ -0,0 +1,3 @@ + 0.01: New Widget + 0.02: swipe left,right update + diff --git a/apps/widviz/eye.png b/apps/widviz/eye.png new file mode 100644 index 000000000..414ad33f5 Binary files /dev/null and b/apps/widviz/eye.png differ diff --git a/apps/widviz/widget.js b/apps/widviz/widget.js new file mode 100644 index 000000000..4282d4c96 --- /dev/null +++ b/apps/widviz/widget.js @@ -0,0 +1,34 @@ +(() => { + + var saved = null; + + function hide(){ + if (!Bangle.isLCDOn() || saved) return; + saved = []; + for (var wd of WIDGETS) { + saved.push(wd.draw); + wd.draw=()=>{}; + } + g.setColor(0,0,0); + g.fillRect(0,0,239,23); + } + + function reveal(){ + if (!Bangle.isLCDOn() || !saved) return; + for (var wd of WIDGETS) wd.draw = saved.shift(); + Bangle.drawWidgets(); + saved=null; + } + + function draw(){ + var img = E.toArrayBuffer(atob("GBgBAAAAAAAAAAAAAAAAAH4AAf+AB4HgDgBwHDw4OH4cMOcMYMMGYMMGMOcMOH4cHDw4DgBwB4HgAf+AAH4AAAAAAAAAAAAAAAAA")); + g.setColor(0x07ff); + g.drawImage(img,this.x,this.y); + } + + WIDGETS["viz"] ={area:"tl", width:24,draw:draw}; + + Bangle.on('swipe',(dir)=>{ + if (dir<0) hide(); else reveal(); + }); +})(); diff --git a/apps/wohrm/ChangeLog b/apps/wohrm/ChangeLog index f5c64dbee..53c451bcd 100644 --- a/apps/wohrm/ChangeLog +++ b/apps/wohrm/ChangeLog @@ -4,3 +4,4 @@ 0.04: Only buzz on high confidence (>85%) 0.05: Improved buzz timing and rendering 0.06: Removed debug outputs, fixed rendering for upper limit, improved rendering for +/- icons, changelog version order fixed +0.07: Home button fixed and README added \ No newline at end of file diff --git a/apps/wohrm/README.md b/apps/wohrm/README.md new file mode 100644 index 000000000..ad9e82525 --- /dev/null +++ b/apps/wohrm/README.md @@ -0,0 +1,29 @@ +# Summary +Workout heart rate monitor that buzzes when your heart rate hits the limits. + +This app is for the [Bangle.js watch](https://banglejs.com/). While active it monitors your heart rate +and will notify you with a buzz whenever your heart rate falls below or jumps above the set limits. + +# How it works +[Try it out](https://www.espruino.com/ide/emulator.html?codeurl=https://raw.githubusercontent.com/msdeibel/BangleApps/master/apps/wohrm/app.js&upload) using the [online Espruino emulator](https://www.espruino.com/ide/emulator.html). + +## Setting the limits +For setting the lower limit press button 4 (left part of the watch's touch screen). +Then adjust the value with the buttons 1 (top) and 3 (bottom) of the watch. + +For setting the upper limit act accordingly after pressing button 5 (the right part of the watch's screen). + +## Reading Reliability +As per the specs of the watch the HR monitor is not 100% reliable all the time. +That's why the WOHRM displays a confidence value for each reading of the current heart rate. + +To the left and right of the "Current" value two colored bars indicate the confidence in +the received value: For 85% and above the bars are green, between 84% and 50% the bars are yellow +and below 50% they turn red. + +## Closing the app +Pressing button 2 (middle) will switch off the HRM of the watch and return you to the launcher. + +# HRM usage +The HRM is switched on when the app is started. It stays switch on while the app is running, even +when the watch screen goes to stand-by. diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index 7e0af4219..d30072a60 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -143,13 +143,13 @@ function renderConfidenceBars(){ if(!confidenceChanged) { return; } if(hrConfidence >= 85){ - g.setColor(0, 255, 0); + g.setColor(0, 255, 0); } else if (hrConfidence >= 50) { - g.setColor(255, 255, 0); + g.setColor(255, 255, 0); } else if(hrConfidence >= 0){ - g.setColor(255, 0, 0); + g.setColor(255, 0, 0); } else { - g.setColor(255, 255, 255); + g.setColor(255, 255, 255); } g.fillRect(45, 110, 55, 150); @@ -287,13 +287,11 @@ function resetHighlightTimeout() { setterHighlightTimeout = setTimeout(setLimitSetterToNone, 2000); } -// Show launcher when middle button pressed function switchOffApp(){ Bangle.setHRMPower(0); Bangle.showLauncher(); } -// special function to handle display switch on Bangle.on('lcdPower', (on) => { g.clear(); if (on) { @@ -312,19 +310,18 @@ Bangle.setHRMPower(1); Bangle.on('HRM', onHrm); setWatch(incrementLimit, BTN1, {edge:"rising", debounce:50, repeat:true}); -setWatch(switchOffApp, BTN2, {edge:"rising", debounce:50, repeat:true}); setWatch(decrementLimit, BTN3, {edge:"rising", debounce:50, repeat:true}); setWatch(setLimitSetterToLower, BTN4, {edge:"rising", debounce:50, repeat:true}); setWatch(setLimitSetterToUpper, BTN5, { edge: "rising", debounce: 50, repeat: true }); +setWatch(switchOffApp, BTN2, {edge:"falling", debounce:50, repeat:true}); + g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); -//drawTrainingHeartRate(); renderHomeIcon(); renderLowerLimitBackground(); renderUpperLimitBackground(); -// refesh every sec setInterval(drawTrainingHeartRate, 1000); diff --git a/apps/worldclock/ChangeLog b/apps/worldclock/ChangeLog new file mode 100644 index 000000000..7d48decd5 --- /dev/null +++ b/apps/worldclock/ChangeLog @@ -0,0 +1,2 @@ +0.01: First try +0.02: Update custom.html for refactor; add README diff --git a/apps/worldclock/README.md b/apps/worldclock/README.md new file mode 100644 index 000000000..058d7775d --- /dev/null +++ b/apps/worldclock/README.md @@ -0,0 +1,20 @@ +# World Clock - See the time in five locations + +In addition to the main clock and date in your current location, you can add up to four other locations. Great for travel or remote working. + +![](worldclock.png) + +## Usage + +Provide names and the UTC offsets for up to four other timezones in the app store. These are stored in a json file on your watch. UTC offsets can be decimal (e.g., 5.5 for India). + +The clock does not handle summer time / daylight saving time changes automatically. If one of your four locations changes its UTC offset, you can simply change the setting in the app store and update. Currently the clock only supports 24 hour time format. + + +## Requests + +[Reach out to Scott](https://www.github.com/computermacgyver) if you have feature requests or notice bugs. + +## Creator + +Made by [Scott Hale](https://www.github.com/computermacgyver), based upon the [Simple Clock](https://github.com/espruino/BangleApps/tree/master/apps/sclock). diff --git a/apps/worldclock/app.js b/apps/worldclock/app.js new file mode 100644 index 000000000..cdbc29cd8 --- /dev/null +++ b/apps/worldclock/app.js @@ -0,0 +1,98 @@ +/* jshint esversion: 6 */ +const timeFontSize = 6; +const dateFontSize = 3; +const gmtFontSize = 2; +const font = "6x8"; + +const xyCenter = g.getWidth() / 2; +const xcol1=10; +const xcol2=g.getWidth()-xcol1; +const yposTime = 75; +const yposDate = 130; +//const yposYear = 175; +//const yposGMT = 220; +const yposWorld=170; + + +var offsets = require("Storage").readJSON("worldclock.settings.json"); + +// Check settings for what type our clock should be +//var is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; +var secondInterval = undefined; + +function doublenum(x) { + return x<10? "0"+x : ""+x; +} + +function offset(dt,offset) { + return new Date(dt.getTime() + (offset*60*60*1000)); +} + +function drawSimpleClock() { + // get date + var d = new Date(); + var da = d.toString().split(" "); + + g.reset(); // default draw styles + // drawSting centered + g.setFontAlign(0, 0); + + // draw time + var time = da[4].substr(0, 5).split(":"); + var hours = time[0], minutes = time[1]; + + g.setFont(font, timeFontSize); + g.drawString(`${hours}:${minutes}`, xyCenter, yposTime, true); + + // draw Day, name of month, Date + var date = [da[0], da[1], da[2]].join(" "); + g.setFont(font, dateFontSize); + + g.drawString(date, xyCenter, yposDate, true); + + // draw year + //g.setFont(font, dateFontSize); + //g.drawString(d.getFullYear(), xyCenter, yposYear, true); + + // draw gmt + //console.log(d.getTimezoneOffset());//offset to GMT in minutes + var gmt = new Date(d.getTime()+(d.getTimezoneOffset()*60*1000)); + //gmt is now UTC+0 + + for (var i=0; i<offsets.length; i++) { + g.setFont(font, gmtFontSize); + dx=offset(gmt,offsets[i][1]); + hours=doublenum(dx.getHours()); + minutes=doublenum(dx.getMinutes()); + g.setFontAlign(-1, 0); + g.drawString(offsets[i][0],xcol1,yposWorld+i*15, true); + g.setFontAlign(1, 0); + g.drawString(`${hours}:${minutes}`, xcol2, yposWorld+i*15, true); + //g.drawString(gmt, xyCenter, yposWorld, true); + } +} + +// clean app screen +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +// refesh every 15 sec when screen is on +Bangle.on('lcdPower',on=>{ + if (secondInterval) clearInterval(secondInterval); + secondInterval = undefined; + if (on) { + secondInterval = setInterval(drawSimpleClock, 15E3); + drawSimpleClock(); // draw immediately + } +}); + +// draw now and every 15 sec until display goes off +drawSimpleClock(); +if (Bangle.isLCDOn()) { + secondInterval = setInterval(drawSimpleClock, 15E3); +} + +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); + diff --git a/apps/worldclock/app.png b/apps/worldclock/app.png new file mode 100755 index 000000000..506fa45b9 Binary files /dev/null and b/apps/worldclock/app.png differ diff --git a/apps/worldclock/custom.html b/apps/worldclock/custom.html new file mode 100644 index 000000000..a857b2f72 --- /dev/null +++ b/apps/worldclock/custom.html @@ -0,0 +1,76 @@ +<html> + <head> + <link rel="stylesheet" href="../../css/spectre.min.css"> + </head> + <body> + + <p>You can add up to 4 timezones. Please give a name and UTC offset in hours. + If you want less than 4, clear the checkbox to the left.</p> + + <table id="worldclock-offsets"> + <tr> + <th>Enabled?</th> + <th>Name</th> + <th>UTC Offset</th> + </tr> + </table> + + <p>Click <button id="upload" class="btn btn-primary">Upload</button></p> + + <script src="../../core/lib/customize.js"></script> + + <script> + + var offsets=[]; + try{ + var stored = localStorage.getItem('worldclock-offset-list') + if(stored) offsets = JSON.parse(stored); + if (!offsets || offsets.length!=4) { + throw "Offsets invalid"; + } + } catch(e){ + offsets=[ + [true,"Tokyo",9], + [true,"Delhi",5.5], + [true, "London",0], + [true, "São Paulo",-3], + ]; + } + console.log(offsets); + var tbl=document.getElementById("worldclock-offsets"); + for (var i=0; i<4; i++) { + var $offset = document.createElement('tr') + $offset.innerHTML = ` + <td><input type="checkbox" id="enabled_${i}" ${offsets[i][0]? "checked" : ""}></td> + <td><input type="text" id="name_${i}" value="${offsets[i][1]}"></td> + <td><input type="number" id="offset_${i}" value="${offsets[i][2]}"></td>` + tbl.append($offset); + } + + // When the 'upload' button is clicked... + document.getElementById("upload").addEventListener("click", function() { + var storage_offsets=[]; + var app_offsets=[]; + for (var i=0; i<4; i++) { + var checked=document.getElementById("enabled_"+i).checked; + var name=document.getElementById("name_"+i).value; + var offset=document.getElementById("offset_"+i).value; + if (checked) { + app_offsets.push([name,offset]); + } + storage_offsets.push([checked,name,offset]); + } + console.log(storage_offsets); + console.log(app_offsets); + localStorage.setItem('worldclock-offset-list',JSON.stringify(storage_offsets)); + // send finished app (in addition to contents of app.json) + sendCustomizedApp({ + storage:[ + {name:"worldclock.settings.json", content:JSON.stringify(app_offsets)}, + ] + }); + }); + + </script> + </body> +</html> diff --git a/apps/worldclock/worldclock-icon.js b/apps/worldclock/worldclock-icon.js new file mode 100644 index 000000000..6e05d254c --- /dev/null +++ b/apps/worldclock/worldclock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgJC/ABEE+EA4EAj9E8HF//gn/gwP///wt/MgF//8gh/8gYLBwEP+EHAofghgFD4EOj//gEPA4ILBGgIxB/wFBgwFB/lsgCKBj/4oxHBvAFBJoV8gP4TQX+gJUBAAN/Aok+AoVgAoXogAfBjkA8AfBAoXAAoUYY4cAiCDEAooA/ABg")) diff --git a/apps/worldclock/worldclock.png b/apps/worldclock/worldclock.png new file mode 100644 index 000000000..e1959ed5b Binary files /dev/null and b/apps/worldclock/worldclock.png differ diff --git a/bin/apploader.js b/bin/apploader.js new file mode 100755 index 000000000..6b4c2202d --- /dev/null +++ b/bin/apploader.js @@ -0,0 +1,261 @@ +#!/usr/bin/nodejs +/* Simple Command-line app loader for Node.js +=============================================== + +NOTE: This needs the '@abandonware/noble' library to be installed. +However we don't want this in package.json (at least +as a normal dependency) because we want `sanitycheck.js` +to be able to run *quickly* in travis for every commit, +and we don't want NPM pulling in (and compiling native modules) +for Noble. +*/ + +var SETTINGS = { + pretokenise : true +}; +var Utils = require("../core/js/utils.js"); +var AppInfo = require("../core/js/appinfo.js"); +var noble; +try { + noble = require('@abandonware/noble'); +} catch (e) {} +if (!noble) try { + noble = require('noble'); +} catch (e) { } +if (!noble) { + console.log("You need to:") + console.log(" npm install @abandonware/noble") + console.log("or:") + console.log(" npm install noble") +} + +var apps; + +function ERROR(msg) { + console.error(msg); + process.exit(1); +} + +try { + apps = JSON.parse(require("fs").readFileSync(__dirname+"/../apps.json")); +} catch(e) { + ERROR("'apps.json' could not be loaded"); +} + +var args = process.argv; + +if (args.length==3 && args[2]=="list") cmdListApps(); +else if (args.length==3 && args[2]=="devices") cmdListDevices(); +else if (args.length==4 && args[2]=="install") cmdInstallApp(args[3]); +else if (args.length==5 && args[2]=="install") cmdInstallApp(args[3], args[4]); +else { + console.log(`apploader.js +------------- + +USAGE: + +apploader.js list + - list available apps +apploader.js devices + - list available device addresses +apploader.js install appname [de:vi:ce:ad:dr:es] +`); +process.exit(0); +} + +function cmdListApps() { + console.log(apps.map(a=>a.id).join("\n")); +} +function cmdListDevices() { + var foundDevices = []; + noble.on('discover', function(dev) { + if (!dev.advertisement) return; + if (!dev.advertisement.localName) return; + var a = dev.address.toString(); + if (foundDevices.indexOf(a)>=0) return; + foundDevices.push(a); + console.log(a,dev.advertisement.localName); + }); + noble.startScanning([], true); + setTimeout(function() { + console.log("Stopping scan"); + noble.stopScanning(); + setTimeout(function() { + process.exit(0); + }, 500); + }, 4000); +} + +function cmdInstallApp(appId, deviceAddress) { + var app = apps.find(a=>a.id==appId); + if (!app) ERROR(`App ${JSON.stringify(appId)} not found`); + if (app.custom) ERROR(`App ${JSON.stringify(appId)} requires HTML customisation`); + return AppInfo.getFiles(app, { + fileGetter:function(url) { + console.log(__dirname+"/"+url); + return Promise.resolve(require("fs").readFileSync(__dirname+"/../"+url).toString("binary")); + }, settings : SETTINGS}).then(files => { + //console.log(files); + var command = files.map(f=>f.cmd).join("\n")+"\n"; + bangleSend(command, deviceAddress).then(() => process.exit(0)); + }); +} + +function bangleSend(command, deviceAddress) { + var log = function() { + var args = [].slice.call(arguments); + console.log("UART: "+args.join(" ")); + } + //console.log("Sending",JSON.stringify(command)); + + var RESET = true; + var DEVICEADDRESS = ""; + if (deviceAddress!==undefined) + DEVICEADDRESS = deviceAddress; + + var complete = false; + var foundDevices = []; + var flowControlPaused = false; + var btDevice; + var txCharacteristic; + var rxCharacteristic; + + return new Promise((resolve,reject) => { + function foundDevice(dev) { + if (btDevice!==undefined) return; + log("Connecting to "+dev.address); + noble.stopScanning(); + connect(dev, function() { + // Connected! + function writeCode() { + log("Writing code..."); + write(command, function() { + complete = true; + btDevice.disconnect(); + }); + } + if (RESET) { + setTimeout(function() { + log("Resetting..."); + write("\x03\x10reset()\n", function() { + setTimeout(writeCode, 1000); + }); + }, 500); + } else + setTimeout(writeCode, 1000); + }); + } + + function connect(dev, callback) { + btDevice = dev; + log("BT> Connecting"); + btDevice.on('disconnect', function() { + log("Disconnected"); + setTimeout(function() { + if (complete) resolve(); + else reject("Disconnected but not complete"); + }, 500); + }); + btDevice.connect(function (error) { + if (error) { + log("BT> ERROR Connecting",error); + btDevice = undefined; + return; + } + log("BT> Connected"); + btDevice.discoverAllServicesAndCharacteristics(function(error, services, characteristics) { + function findByUUID(list, uuid) { + for (var i=0;i<list.length;i++) + if (list[i].uuid==uuid) return list[i]; + return undefined; + } + + var btUARTService = findByUUID(services, "6e400001b5a3f393e0a9e50e24dcca9e"); + txCharacteristic = findByUUID(characteristics, "6e400002b5a3f393e0a9e50e24dcca9e"); + rxCharacteristic = findByUUID(characteristics, "6e400003b5a3f393e0a9e50e24dcca9e"); + if (error || !btUARTService || !txCharacteristic || !rxCharacteristic) { + log("BT> ERROR getting services/characteristics"); + log("Service "+btUARTService); + log("TX "+txCharacteristic); + log("RX "+rxCharacteristic); + btDevice.disconnect(); + txCharacteristic = undefined; + rxCharacteristic = undefined; + btDevice = undefined; + return openCallback(); + } + + rxCharacteristic.on('data', function (data) { + var s = ""; + for (var i=0;i<data.length;i++) { + var ch = data[i]; + if (ch==19) { + log("XOFF"); + flowControlPaused = 200; + } else if (ch==17) { + log("XON"); + flowControlPaused = false; + } else + s+=String.fromCharCode(ch); + } + log("Received", JSON.stringify(s)); + }); + rxCharacteristic.subscribe(function() { + callback(); + }); + }); + }); + }; + + function write(data, callback) { + var amt = 0; + var total = data.length; + var progress=0; + + function writeAgain() { + if (flowControlPaused) { + flowControlPaused--; + if (flowControlPaused==0) + log("TIMEOUT - sending"); + setTimeout(writeAgain,50); + return; + } + if (!data.length) return callback(); + var d = data.substr(0,20); + data = data.substr(20); + var buf = new Buffer.alloc(d.length); + progress++; + if (progress>=10) { + log("Writing "+amt+"/"+total); + progress=0; + } + //log("Writing ",JSON.stringify(d)); + amt += d.length; + for (var i = 0; i < buf.length; i++) + buf.writeUInt8(d.charCodeAt(i), i); + txCharacteristic.write(buf, false, writeAgain); + } + writeAgain(); + } + + function disconnect() { + btDevice.disconnect(); + } + + log("Discovering..."); + noble.on('discover', function(dev) { + if (!dev.advertisement) return; + if (!dev.advertisement.localName) return; + var a = dev.address.toString(); + if (foundDevices.indexOf(a)>=0) return; + foundDevices.push(a); + log("Found device: ",a,dev.advertisement.localName); + if (a == DEVICEADDRESS) + return foundDevice(dev); + else if (DEVICEADDRESS=="" && dev.advertisement.localName.indexOf("Bangle.js")==0) { + return foundDevice(dev); + } + }); + noble.startScanning([], true); + }); +} diff --git a/bin/firmwaremaker.js b/bin/firmwaremaker.js index e5db392dd..ce885c394 100755 --- a/bin/firmwaremaker.js +++ b/bin/firmwaremaker.js @@ -3,6 +3,9 @@ Mashes together a bunch of different apps to make a single firmware JS file which can be uploaded. */ +var SETTINGS = { + pretokenise : true +}; var path = require('path'); var ROOTDIR = path.join(__dirname, '..'); @@ -16,7 +19,7 @@ var APPS = [ // IDs of apps to install var MINIFY = true; var fs = require("fs"); -var AppInfo = require(ROOTDIR+"/appinfo.js"); +var AppInfo = require(ROOTDIR+"/core/js/appinfo.js"); var appjson = JSON.parse(fs.readFileSync(APPJSON).toString()); var appfiles = []; @@ -36,20 +39,23 @@ function fileGetter(url) { if (url.endsWith(".json")) { var f = url.slice(0,-5); console.log("MINIFYING JSON "+f); - var j = eval("("+fs.readFileSync(url).toString()+")"); + var j = eval("("+fs.readFileSync(url).toString("binary")+")"); var code = JSON.stringify(j); //console.log(code); url = f+".min.json"; fs.writeFileSync(url, code); } } - return Promise.resolve(fs.readFileSync(url).toString()); + return Promise.resolve(fs.readFileSync(url).toString("binary")); } Promise.all(APPS.map(appid => { var app = appjson.find(app=>app.id==appid); if (app===undefined) throw new Error(`App ${appid} not found`); - return AppInfo.getFiles(app, fileGetter).then(files => { + return AppInfo.getFiles(app, { + fileGetter : fileGetter, + settings : SETTINGS + }).then(files => { appfiles = appfiles.concat(files); }); })).then(() => { diff --git a/bin/pre-publish.sh b/bin/pre-publish.sh new file mode 100755 index 000000000..ee73968d7 --- /dev/null +++ b/bin/pre-publish.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +cd `dirname $0`/.. +nodejs bin/sanitycheck.js || exit 1 + +echo "Sanity check passed." + +echo "Finding app dates..." + +# Create list of: +# appid,created_time,modified_time +cd apps +for appfolder in *; do + echo "$appfolder,$(git log --follow --format=%ai -- $appfolder | tail -n 1),$(git log --follow --format=%ai -- $appfolder | head -n 1)" ; +done | grep -v _example_ | grep -v unknown.png > ../appdates.csv +cd .. + +echo "Ready to publish" diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index 62b111ae0..4bdad1a9a 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -27,22 +27,52 @@ function WARN(s) { var appsFile, apps; try { - appsFile = fs.readFileSync(BASEDIR+"apps.json"); + appsFile = fs.readFileSync(BASEDIR+"apps.json").toString(); } catch (e) { ERROR("apps.json not found"); } try{ apps = JSON.parse(appsFile); } catch (e) { + console.log(e); + var m = e.toString().match(/in JSON at position (\d+)/); + if (m) { + var char = parseInt(m[1]); + console.log("==============================================="); + console.log("LINE "+appsFile.substr(0,char).split("\n").length); + console.log("==============================================="); + console.log(appsFile.substr(char-10, 20)); + console.log("==============================================="); + } + console.log(m); ERROR("apps.json not valid JSON"); + } const APP_KEYS = [ 'id', 'name', 'shortName', 'version', 'icon', 'description', 'tags', 'type', - 'sortorder', 'readme', 'custom', 'interface', 'storage', 'allow_emulator', + 'sortorder', 'readme', 'custom', 'interface', 'storage', 'data', 'allow_emulator', + 'dependencies' ]; const STORAGE_KEYS = ['name', 'url', 'content', 'evaluate']; +const DATA_KEYS = ['name', 'wildcard', 'storageFile']; +const FORBIDDEN_FILE_NAME_CHARS = /[,;]/; // used as separators in appid.info +const VALID_DUPLICATES = [ '.tfmodel', '.tfnames' ]; +function globToRegex(pattern) { + const ESCAPE = '.*+-?^${}()|[]\\'; + const regex = pattern.replace(/./g, c => { + switch (c) { + case '?': return '.'; + case '*': return '.*'; + default: return ESCAPE.includes(c) ? ('\\' + c) : c; + } + }); + return new RegExp('^'+regex+'$'); +} +const isGlob = f => /[?*]/.test(f) +// All storage+data files in all apps: {app:<appid>,[file:<storage.name> | data:<data.name|data.wildcard>]} +let allFiles = []; apps.forEach((app,appIdx) => { if (!app.id) ERROR(`App ${appIdx} has no id`); //console.log(`Checking ${app.id}...`); @@ -71,12 +101,25 @@ apps.forEach((app,appIdx) => { if (app.readme && !fs.existsSync(appDir+app.readme)) ERROR(`App ${app.id} README file doesn't exist`); if (app.custom && !fs.existsSync(appDir+app.custom)) ERROR(`App ${app.id} custom HTML doesn't exist`); if (app.interface && !fs.existsSync(appDir+app.interface)) ERROR(`App ${app.id} interface HTML doesn't exist`); + if (app.dependencies) { + if (("object"==typeof app.dependencies) && !Array.isArray(app.dependencies)) { + Object.keys(app.dependencies).forEach(dependency => { + if (app.dependencies[dependency]!="type") + ERROR(`App ${app.id} 'dependencies' must all be tagged 'type' right now`); + }); + } else + ERROR(`App ${app.id} 'dependencies' must be an object`); + } var fileNames = []; app.storage.forEach((file) => { if (!file.name) ERROR(`App ${app.id} has a file with no name`); + if (isGlob(file.name)) ERROR(`App ${app.id} storage file ${file.name} contains wildcards`); + let char = file.name.match(FORBIDDEN_FILE_NAME_CHARS) + if (char) ERROR(`App ${app.id} storage file ${file.name} contains invalid character "${char[0]}"`) if (fileNames.includes(file.name)) ERROR(`App ${app.id} file ${file.name} is a duplicate`); fileNames.push(file.name); + allFiles.push({app: app.id, file: file.name}); if (file.url) if (!fs.existsSync(appDir+file.url)) ERROR(`App ${app.id} file ${file.url} doesn't exist`); if (!file.url && !file.content && !app.custom) ERROR(`App ${app.id} file ${file.name} has no contents`); var fileContents = ""; @@ -115,6 +158,54 @@ apps.forEach((app,appIdx) => { if (!STORAGE_KEYS.includes(key)) ERROR(`App ${app.id}'s ${file.name} has unknown key ${key}`); } }); + let dataNames = []; + (app.data||[]).forEach((data)=>{ + if (!data.name && !data.wildcard) ERROR(`App ${app.id} has a data file with no name`); + if (dataNames.includes(data.name||data.wildcard)) + ERROR(`App ${app.id} data file ${data.name||data.wildcard} is a duplicate`); + dataNames.push(data.name||data.wildcard) + allFiles.push({app: app.id, data: (data.name||data.wildcard)}); + if ('name' in data && 'wildcard' in data) + ERROR(`App ${app.id} data file ${data.name} has both name and wildcard`); + if (isGlob(data.name)) + ERROR(`App ${app.id} data file name ${data.name} contains wildcards`); + if (data.wildcard) { + if (!isGlob(data.wildcard)) + ERROR(`App ${app.id} data file wildcard ${data.wildcard} does not actually contains wildcard`); + if (data.wildcard.replace(/\?|\*/g,'') === '') + ERROR(`App ${app.id} data file wildcard ${data.wildcard} does not contain regular characters`); + else if (data.wildcard.replace(/\?|\*/g,'').length < 3) + WARN(`App ${app.id} data file wildcard ${data.wildcard} is very broad`); + else if (!data.wildcard.includes(app.id)) + WARN(`App ${app.id} data file wildcard ${data.wildcard} does not include app ID`); + } + let char = (data.name||data.wildcard).match(FORBIDDEN_FILE_NAME_CHARS) + if (char) ERROR(`App ${app.id} data file ${data.name||data.wildcard} contains invalid character "${char[0]}"`) + if ('storageFile' in data && typeof data.storageFile !== 'boolean') + ERROR(`App ${app.id} data file ${data.name||data.wildcard} has non-boolean value for "storageFile"`); + for (const key in data) { + if (!DATA_KEYS.includes(key)) + ERROR(`App ${app.id} data file ${data.name||data.wildcard} has unknown property "${key}"`); + } + }); + // prefer "appid.json" over "appid.settings.json" (TODO: change to ERROR once all apps comply?) + if (dataNames.includes(app.id+".settings.json") && !dataNames.includes(app.id+".json")) + WARN(`App ${app.id} uses data file ${app.id+'.settings.json'} instead of ${app.id+'.json'}`) + // settings files should be listed under data, not storage (TODO: change to ERROR once all apps comply?) + if (fileNames.includes(app.id+".settings.json")) + WARN(`App ${app.id} uses storage file ${app.id+'.settings.json'} instead of data file`) + if (fileNames.includes(app.id+".json")) + WARN(`App ${app.id} uses storage file ${app.id+'.json'} instead of data file`) + // warn if storage file matches data file of same app + dataNames.forEach(dataName=>{ + const glob = globToRegex(dataName) + fileNames.forEach(fileName=>{ + if (glob.test(fileName)) { + if (isGlob(dataName)) WARN(`App ${app.id} storage file ${fileName} matches data wildcard ${dataName}`) + else WARN(`App ${app.id} storage file ${fileName} is also listed in data`) + } + }) + }) //console.log(fileNames); if (isApp && !fileNames.includes(app.id+".app.js")) ERROR(`App ${app.id} has no entrypoint`); if (isApp && !fileNames.includes(app.id+".img")) ERROR(`App ${app.id} has no JS icon`); @@ -123,3 +214,22 @@ apps.forEach((app,appIdx) => { if (!APP_KEYS.includes(key)) ERROR(`App ${app.id} has unknown key ${key}`); } }); +// Do not allow files from different apps to collide +let fileA +while(fileA=allFiles.pop()) { + if (VALID_DUPLICATES.includes(fileA.file)) + return; + const nameA = (fileA.file||fileA.data), + globA = globToRegex(nameA), + typeA = fileA.file?'storage':'data' + allFiles.forEach(fileB => { + const nameB = (fileB.file||fileB.data), + globB = globToRegex(nameB), + typeB = fileB.file?'storage':'data' + if (globA.test(nameB)||globB.test(nameA)) { + if (isGlob(nameA)||isGlob(nameB)) + ERROR(`App ${fileB.app} ${typeB} file ${nameB} matches app ${fileA.app} ${typeB} file ${nameA}`) + else ERROR(`App ${fileB.app} ${typeB} file ${nameB} is also listed as ${typeA} file for app ${fileA.app}`) + } + }) +} diff --git a/core b/core new file mode 160000 index 000000000..9708e1a15 --- /dev/null +++ b/core @@ -0,0 +1 @@ +Subproject commit 9708e1a15ee20734a24f6f2913078aa8bba625dc diff --git a/css/main.css b/css/main.css new file mode 100644 index 000000000..4acddf0dc --- /dev/null +++ b/css/main.css @@ -0,0 +1,34 @@ +.navbar { background-color: #5755d9; padding: 0.5em 1em 0.5em 1em; } +.navbar .navbar-brand { + color: #fff; + font-weight: bold; +} +.avatar img { + border-radius: 5px 5px 5px 5px; + background: #ddd; +} +#toastcontainer { + position:fixed; + bottom:8px;left:0px;right:0px; + z-index: 100; +} +.hero { + padding-bottom: 1rem; + padding-top: 1rem; + text-align:center; +} +.chip { + cursor: pointer; +} +.filter-nav { + display: inline-block; +} +.sort-nav { + float: right; +} +.tile-content { position: relative; } +.link-github { + position:absolute; + top: 36px; + left: -24px; +} diff --git a/img/github-icon-sml.png b/img/github-icon-sml.png deleted file mode 100644 index 81ca8f22e..000000000 Binary files a/img/github-icon-sml.png and /dev/null differ diff --git a/img/github-icon.png b/img/github-icon.png deleted file mode 100644 index aadd0fab9..000000000 Binary files a/img/github-icon.png and /dev/null differ diff --git a/index.html b/index.html index f016ffb49..5aabed4df 100644 --- a/index.html +++ b/index.html @@ -2,11 +2,12 @@ <html lang="en"> <head> <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <meta name="viewport" content="width=device-width, initial-scale=0.8,maximum-scale=0.8, minimum-scale=0.8, shrink-to-fit=no"> <link rel="stylesheet" href="css/spectre.min.css"> <link rel="stylesheet" href="css/spectre-exp.min.css"> <link rel="stylesheet" href="css/spectre-icons.min.css"> <link rel="stylesheet" href="css/pwa.css"> + <link rel="stylesheet" href="css/main.css"> <link rel="apple-touch-icon" sizes="180x180" href="img/apple-touch-icon.png"> <link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png"> @@ -17,36 +18,6 @@ <meta name="msapplication-TileColor" content="#5755d9"> <meta name="theme-color" content="#5755d9"> <title>Bangle.js App Loader -